This Pure CSS Morphing Dark Mode Toggle is a sophisticated implementation of a theme switcher that eliminates the need for JavaScript. By utilizing the modern CSS :has() relational selector and complex transform logic, the component morphs a sun icon into a moon icon seamlessly. It offers a premium feel through the use of custom cubic-bezier timing and modular CSS construction.
Core Technique
The component achieves its goal through two main technical pillars: parent-state detection via :has() and a multi-part geometric icon system.
1. Parent Theming via :has()
Traditionally, switching themes without JS required the “Checkbox Hack” where only sibling elements could be styled. With the :has() selector, the state of the checkbox can now control the body or any parent container directly.
/* Toggling the entire page theme based on checkbox state */
body:has(.switch__input:checked) {
background-color: hsl(var(--hue), 10%, 10%);
color: hsl(var(--hue), 10%, 90%);
}
2. The Morphing Icon System
The icon isn’t an SVG; it’s a collection of 11 span elements (icon parts).
- Sun Rays: Parts 4 through 11 are positioned around a center point using
transform-origin: 50% 0and rotated in 45-degree increments. - Transition: When checked, the sun rays scale to zero (
scale(0)) while the center core (part--3) changes itsbox-shadowto create the crescent moon shape.
.switch__icon-part--3 {
box-shadow: 0 0 0 0.625em hsl(var(--hue),10%,10%) inset;
transform: scale(0.25);
}
/* Morphing into the moon shape */
.switch__input:checked ~ .switch__icon .switch__icon-part--3 {
box-shadow: 0 0 0 0.25em hsl(var(--hue),10%,10%) inset;
transform: scale(1);
}
Browser Support
The critical factor for this snippet is the :has() selector. While supported in the latest versions of all major browsers, it is a relatively new addition to the CSS specification.
This code works perfectly in all modern browsers. Users on older versions of Firefox (pre-December 2023) or legacy browsers will see the functional checkbox but the theme switching logic and morphing animation will not trigger.


