A switch stood on its end: the knob rises to turn it on, with ON and OFF marks beside the track that light up in turn. Handy in narrow side panels, mixer strips and hardware style dashboards.
Also known as: vertical toggle switch css, up down switch, vertical on off switch.
<label class="tgl-vertical"> <input type="checkbox" role="switch" aria-label="Main power"> <span class="tgl-vertical-track" aria-hidden="true"></span> <span class="tgl-vertical-marks" aria-hidden="true"><span>ON</span><span>OFF</span></span> </label>
.tgl-vertical {
--c: var(--tgl-color, #3b82f6);
font-size: var(--tgl-size, 24px);
position: relative;
display: inline-flex;
vertical-align: middle;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
gap: 0.55em;
font-family: system-ui, sans-serif;
font-weight: 700;
}
.tgl-vertical input {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
z-index: 1;
}
.tgl-vertical-track {
position: relative;
width: 2em;
height: 3.6em;
border-radius: 1em;
background: color-mix(in srgb, currentColor 13%, transparent);
transition: background-color 0.3s ease;
}
.tgl-vertical-track::before {
content: "";
position: absolute;
bottom: 0.2em;
left: 0.2em;
width: 1.6em;
height: 1.6em;
border-radius: 50%;
background: #fff;
box-shadow: 0 0.1em 0.3em rgb(0 0 0 / 0.25);
transition: transform 0.35s cubic-bezier(0.3, 0.7, 0.3, 1);
}
.tgl-vertical-marks {
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 0.85em 0;
font-size: 0.6em;
letter-spacing: 0.1em;
}
.tgl-vertical-marks span {
color: color-mix(in srgb, currentColor 35%, transparent);
transition: color 0.3s ease;
}
.tgl-vertical input:not(:checked) ~ .tgl-vertical-marks span:last-child { color: inherit; }
.tgl-vertical input:checked ~ .tgl-vertical-marks span:first-child { color: var(--c); }
.tgl-vertical input:checked + .tgl-vertical-track { background: var(--c); }
.tgl-vertical input:checked + .tgl-vertical-track::before { transform: translateY(-1.6em); }
.tgl-vertical input:focus-visible + .tgl-vertical-track {
outline: 2px solid var(--c);
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
.tgl-vertical, .tgl-vertical *, .tgl-vertical::before, .tgl-vertical::after, .tgl-vertical *::before, .tgl-vertical *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--tgl-color on the element or a parent.
Currently previewing #3b82f6.--tgl-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 24px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.