BYTETOOLS

CSS Toggle Switch Generator

Generate an accessible CSS toggle switch built on a real checkbox, with focus-visible ring, disabled state, reduced-motion support and copyable HTML and CSS.

Live preview

Switch settings

56
32
4
200
Track (off)
Track (on)
Knob
Focus ring

Geometry and contrast

Knob diameter 24px, travel 24px.

On vs off track contrast 3.86:1.

Knob on the “on” track 5.70:1.

Knob on the “off” track 1.48:1.

The weakest boundary here is 1.48:1, below the 3:1 that WCAG 2.1 success criterion 1.4.11 asks of non-text UI components. Someone with low vision may not be able to tell the on state from the off state. Darken the “on” track or the knob until every pairing above clears 3:1.

HTML

<label class="toggle">
  <input type="checkbox" class="toggle__input">
  <span class="toggle__track"></span>
  <span class="toggle__label">Enable notifications</span>
</label>

CSS

.toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  cursor: pointer;
  user-select: none;
}

/* Visually hidden, but still focusable and readable by assistive tech. */
.toggle__input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.toggle__track {
  position: relative;
  display: block;
  flex: none;
  width: 56px;
  height: 32px;
  border-radius: 16px;
  background-color: #d4d4d8;
  transition: background-color 200ms ease;
}

.toggle__track::before {
  content: "";
  position: absolute;
  top: 4px;
  left: 4px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background-color: #ffffff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: transform 200ms ease;
}

.toggle__input:checked + .toggle__track {
  background-color: #7c3aed;
}

.toggle__input:checked + .toggle__track::before {
  transform: translateX(24px);
}

/* Keyboard focus only — a mouse click will not draw the ring. */
.toggle__input:focus-visible + .toggle__track {
  outline: 2px solid #7c3aed;
  outline-offset: 2px;
}

.toggle__input:disabled + .toggle__track {
  opacity: 0.5;
  cursor: not-allowed;
}

.toggle:has(.toggle__input:disabled) {
  cursor: not-allowed;
}

@media (prefers-reduced-motion: reduce) {
  .toggle__track,
  .toggle__track::before {
    transition-duration: 0ms;
  }
}

The markup is a real input[type=checkbox] wrapped in alabel, so it is keyboard operable, announced correctly by screen readers, and submits with a form — none of which is true of a divwith a click handler. The input is visually hidden rather than display: none, which would remove it from the tab order entirely.

What is the CSS Toggle Switch Generator?

A toggle switch is just a checkbox wearing a costume. The version this tool generates keeps the real input in the markup — visually hidden but still focusable — and styles a sibling span as the track, with a pseudo-element sliding across as the knob.

  • Built on a real checkbox, so it is keyboard and screen-reader friendly
  • Knob size and travel derived automatically so it can never overflow
  • Focus-visible ring and a disabled state included
  • Reduced-motion block that disables the transition
  • Contrast read-outs for on, off and knob, with a WCAG warning
  • Copyable HTML and CSS with the label text properly escaped

How to use the CSS Toggle Switch Generator

  1. 1

    Set the track width and height, the knob inset and the transition duration.

  2. 2

    Choose the off track, on track, knob and focus ring colours.

  3. 3

    Type the label text and decide whether it should be visible or an aria-label.

  4. 4

    Toggle the checked and disabled preview boxes to check both states.

  5. 5

    Copy the HTML and the CSS — they are designed to be pasted together.

About the CSS Toggle Switch Generator

A toggle switch is just a checkbox wearing a costume. The version this tool generates keeps the real input in the markup — visually hidden but still focusable — and styles a sibling span as the track, with a pseudo-element sliding across as the knob. That means it works with the keyboard, announces correctly to screen readers, and submits with a form.

Set the track size, knob inset, transition duration and four colours, and the preview updates live. The generated CSS includes a focus-visible ring so keyboard users get a clear indicator without mouse users seeing an outline on click, a disabled state, and a reduced-motion block that switches off the animation for people who ask for that.

The tool also measures the contrast between the on and off states and warns when it falls below the 3:1 that WCAG asks of non-text UI. Everything is generated in your browser with nothing uploaded.

Frequently asked questions

How do you make a toggle switch in CSS?

Hide a checkbox visually, put a span next to it for the track, and use a pseudo-element as the knob. The :checked selector then changes the track colour and translates the knob across. The important part is hiding the input with clip rather than display: none, so it stays focusable.

Should a toggle switch be a checkbox or a button?

A checkbox is the safer default. It is a native form control that submits its value, works with the keyboard for free, and needs no JavaScript. A button with role=switch is also valid and reads slightly better to some screen readers, but you then have to manage the checked state yourself.

Why should I use focus-visible instead of focus?

Because :focus draws the ring whenever the control receives focus, including on a mouse click, which designers often respond to by removing it altogether — and that leaves keyboard users stranded. :focus-visible only fires when the browser thinks a focus indicator is genuinely needed, so keyboard users keep it.

Do I need to add ARIA attributes to a CSS toggle switch?

Not with this markup. A checkbox inside a label is already announced as a checkbox with its state and name, which is what assistive technology needs. If you turn the visible label off, this tool moves the text into an aria-label so the control is never left unnamed.

What contrast do toggle switches need to pass WCAG?

WCAG 2.1 success criterion 1.4.11 asks for at least 3:1 between a control and adjacent colours, and between the states that carry meaning. That means your on and off track colours need to differ by 3:1, not just look different. The tool measures all three pairings and flags the weakest.

Related tools