AI CSS Animations

Vertical Toggle Switch

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.

HTML

<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>

CSS

.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;
  }
}

Customizing this snippet

  • Color: set --tgl-color on the element or a parent. Currently previewing #3b82f6.
  • Size: set --tgl-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 24px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar toggle switches