Advertisement

Interactive CSS Light Bulb Toggle

| | 2 min read | code by Abubaker Saeed
Intermediate

Tech & Dependencies

HTML CSS JavaScript

Features

  • CSS Drawing
  • Dark Mode Switch
  • Click Micro-interaction
  • Tactile Feedback

Browser Support

Chrome 80+ Edge 80+ Safari 13+ Firefox 70+

Core

This Interactive CSS Light Bulb Toggle transforms a standard theme switch into a playful interaction. It creates a convincing illusion of a physical pull-cord using standard click events. Rather than using a complex physics engine, it relies on precise timing between mouse/touch events and CSS transforms to mimic the tension and release of a rope when the user clicks the button.

Core Technique

The component consists of three main layers: the CSS drawing, the variable-based theming, and the event-driven animation.

1. CSS Geometry & Drawing

The light bulb is not an SVG or image; it is constructed entirely from HTML elements styled with CSS borders and transforms. The “glass” bulb uses a border-radius of 100px, while the filament wires are created using rotated divs.

.line-1 {
  /* Creating angled filament wires */
  width: 10px;
  height: 30px;
  border-bottom: 0;
  transform: rotate(-30deg) translateX(-3px) translateY(50%);
}

2. HSL Variable Theming

The visual change between “Day” and “Night” is handled instantly by toggling a class on the body. The CSS uses HSL variables, allowing for sweeping color changes by modifying just a few lines of code. When the .on class is added, the background becomes dark blue, and the bulb parts adjust contrast accordingly.

body {
  /* Day Theme */
  --global-bg: hsl(222 4% 96%);
  --global-s: hsl(222 99% 46%);
}

body.on {
  /* Night Theme */
  --global-bg: hsl(228 100% 4%);
  --global-s: hsl(254 100% 83%);
}

3. Tactile Feedback via Events

The “pull” effect is a micro-interaction triggered by the button’s press state. The JavaScript separates the mousedown (press) and mouseup (release) events to manipulate the rope element (.lower-2).

  1. Press: The rope translates down (translateY(0)), creating the sensation of tension.
  2. Release: The rope snaps back up (translateY(-4px)), completing the “switch” feeling.
// Simulate tension on press
stateToggle.addEventListener("mousedown", () => {
  l2.style.transform = "translateX(13px) translateY(0)";
});

// Snap back on release
stateToggle.addEventListener("mouseup", () => {
  l2.style.transform = "translateX(13px) translateY(-4px)";
});

Accessibility (A11y)

  • Focusable: The main interaction is wrapped in a <button>, which is excellent for keyboard navigation.
  • State Indication: The button lacks an aria-pressed or aria-label attribute to indicate the current state (Light/Dark) to screen readers.
  • Motion: The swinging animation runs infinitely. It should be wrapped in a @media (prefers-reduced-motion: reduce) query to pause for users sensitive to motion.

Browser Support

The snippet uses standard modern CSS and Vanilla JavaScript. It is compatible with all major browsers.

Advertisement