Neumorphic Light and Wall Switch 🤤 using HTML, CSS & JS

 

Flipping the Switch on Dark Mode: Building a Realistic, Dynamic CSS Lamp and Neumorphic Switchboard

We’ve all seen standard dark mode toggles—the classic sun/moon icon in the navbar. But what if we made "flipping the switch" a truly tactile, satisfying experience?

Today, we're going to dive into a creative frontend experiment: building a fully interactive room lighting scene in pure CSS and HTML (with just a tiny dash of JavaScript). This isn't just a background color change; it’s a dynamic, photorealistic hanging lamp and a detailed wall switchboard that both fall into shadow when the light is off.

Let's break down the design principles and CSS tricks that made this project light up.

The Vision: An Immersive Lighting Fixture

The goal was to create a scene with two main components:

  1. A Realistic Hanging Lamp: A classic trapezoid shade that casts a perfectly aligned beam of light.

  2. A Neumorphic Switchboard: A physical fixture mounted on the wall with that signature "extruded plastic" neumorphic feel, complete with an glowing power icon.

The real challenge? Making the physical fixtures themselves fall into deep shadow when the room is dark.

Deep Dive into Key CSS Techniques

This project looks complex, but it’s actually a combination of several straightforward, powerful CSS features.

1. Dynamic Shadows: The Secret to Realism

This was the most crucial detail. When the room light goes off, the lamp shade shouldn't stay its bright illuminated color; it must fall into shadow.

We solved this using CSS Variables and Transitions. When the body class changes to .is-on, we don't just fade the light beam; we smoothly transition the color of the lamp shade and the switchboard plate.

CSS
:root {
  /* Lamp Shade Colors */
  --lamp-shade-off: #0b0c10; /* Blends into dark room */
  --lamp-shade-on: #2d3243;  /* Illuminated blue/grey */
  ...
}

/* Base shade state */
.lamp-shade {
  background-color: var(--lamp-shade-off);
  transition: all 0.6s ease;
}

/* Light ON shade state */
body.is-on .lamp-shade {
  background-color: var(--lamp-shade-on);
}

The subtle highlights on the screws of the switchboard and the outer rim of the button also fade away in the dark, mimicking the absence of an ambient light source.

2. Mastering alignment with clip-path

Creating a trapezoid lamp shade and a spreading beam of light requires the polygon() function in clip-path. However, making them align perfectly can be tricky.

The trick is math. We made the light beam much wider (500px) than the lamp shade (170px). By setting the clip-path coordinates for the top of the beam to 33% and 67%, we ensured the top opening was exactly 170px wide, creating a perfect, seamless connection.

CSS
.light-beam {
  width: 500px;
  /* Top edge math: (500px * 0.33) to (500px * 0.67) = approx 170px gap */
  clip-path: polygon(33% 0%, 67% 0%, 100% 100%, 0% 100%);
}

3. Solving the "Smooth Fade" (Pseudo-Elements)

Originally, transitioning the background from a solid dark color to a glowing radial gradient caused a momentary white "flash." CSS gradients don't transition smoothly.

The fix was to move the wall glow gradient to a separate layer using the ::before pseudo-element on the body.

CSS
body::before {
  content: "";
  position: absolute;
  /* Full radial glow gradient */
  background: radial-gradient(circle at 35% 40%, ...);
  opacity: 0; /* Hidden by default */
  transition: opacity 0.6s ease;
}

body.is-on::before {
  opacity: 1; /* Smoothly fade the gradient in */
}

This allows us to transition the opacity, resulting in a buttery smooth fade with zero flashing issues.

4. The Neumorphic Switchboard UI

The switchboard combines neumorphic ("soft UI") and skeuomorphic (realistic detail) trends. We used layered shadows to make the switchboard plate look like it’s subtly raised off the wall, and the button itself looks satisfyingly pressable. The addition of four tiny "inset" screws completes the look.

CSS
.switch-board {
  /* Raises the board off the wall */
  box-shadow: 10px 15px 30px rgba(0,0,0,0.6);
  /* Engraves the screws and edges */
  box-shadow: inset 2px 2px 5px rgba(255,255,255,0.05);
}

The power icon itself (a free SVG from the excellent Feather Icons) acts as the indicator light, glowing blue only when the switch is in the :checked state.

You can use https://lucide.dev/ for icons

How the Logic Works

While the design is heavy CSS, the interaction is simple HTML and JavaScript.

  1. We used an HTML <input type="checkbox"> hidden inside a <label>. The checkbox handles the true/false (ON/OFF) state.

  2. A tiny bit of JavaScript listens for the checkbox to change.

  3. When it changes, we toggle the class .is-on on the <body> element.

To know More about it click below the youtube icon - 


Previous Post Next Post