Toggle (CSS Only Trick)
A fully CSS toggle built on a visually hidden checkbox and the :has() selector. Checking the box shifts the dot with a bouncy transition, changes the label color, and changes the section background — all without JavaScript.
Code
<section class="section-resource">
<div class="btn-toggle">
<div class="btn-toggle__toggle">
<div class="btn-toggle__toggle-dot"></div>
</div>
<p class="btn-toggle__p">I'm a toggle</p>
<input type="checkbox" class="btn-toggle__checkbox">
</div>
</section>.section-resource {
background-color: #e4d8d5;
justify-content: center;
align-items: center;
min-height: 100vh;
font-size: 4em;
display: flex;
transition: background-color 0.4s cubic-bezier(0.35, 1, 0.6, 1);
}
.btn-toggle {
grid-column-gap: .5em;
grid-row-gap: .5em;
cursor: pointer;
align-items: center;
display: flex;
position: relative;
}
.btn-toggle__toggle {
background-color: #ff4c24;
border-radius: 2em;
flex-shrink: 0;
width: 2em;
height: 1.25em;
display: flex;
}
.btn-toggle__toggle-dot {
background-color: #fff;
border-radius: 50%;
width: 1em;
height: 1em;
margin-top: .125em;
margin-left: .125em;
transition: all 0.4s cubic-bezier(0.35, 1.5, 0.6, 1);
transform: translateX(0em) rotate(0.001deg);
}
.btn-toggle__p {
margin-bottom: 0;
font-size: 1.25em;
line-height: 1;
position: relative;
transition: color 0.4s cubic-bezier(0.35, 1, 0.6, 1);
}
.btn-toggle__checkbox {
opacity: 0;
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 100%;
position: absolute;
cursor: pointer;
}
@media screen and (max-width: 767px) {
.section-resource {
font-size: 7vw;
}
}
/* Animations based on :checked */
.section-resource:has(input[type="checkbox"]:checked) {
background: #301139;
}
.btn-toggle:has(input[type="checkbox"]:checked) .btn-toggle__toggle-dot {
transform: translateX(0.75em) rotate(0.001deg);
}
.btn-toggle:has(input[type="checkbox"]:checked) .btn-toggle__p {
color: #EFEEEC;
}Guide
The :has() Trick
The checkbox is hidden with opacity: 0 and stretched over the entire toggle using position: absolute and width/height 100%, so clicking anywhere on the component toggles it. :has(input:checked) on a parent selector then drives all visual changes in pure CSS.
Dot Movement
The dot uses translateX(0.75em) when checked to slide to the right. The cubic-bezier(0.35, 1.5, 0.6, 1) overshoot gives it a bouncy landing. rotate(0.001deg) is a GPU compositing hint to keep the animation smooth.
Extending It
Any element inside or outside the toggle can be styled based on the checked state as long as you can reach it with a :has() selector on a shared ancestor. Change colours, swap icons, show/hide elements — all without JavaScript.