Skip to content
Plinth

Original by Plinth · MIT

Forms

Toggle Switch

An accessible switch with a satisfying overshoot when it lands.

#toggle#switch#form#css

Install

npx shadcn@latest add https://plinthui.com/r/toggle-switch.json
Open in v0
'use client';

import { useState } from 'react';

export function ToggleSwitch({
  label = 'Notifications',
  initialChecked = false,
  onChange,
}: {
  label?: string;
  initialChecked?: boolean;
  onChange?: (checked: boolean) => void;
}) {
  const [checked, setChecked] = useState(initialChecked);

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setChecked(event.target.checked);
    onChange?.(event.target.checked);
  };

  const thumbStyle: React.CSSProperties = {
    transform: checked ? 'translateX(20px)' : 'translateX(0px)',
    transition: 'transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1)',
  };

  return (
    <label className="relative inline-flex cursor-pointer select-none items-center gap-2.5 text-sm text-[#6f6d64] dark:text-[#8a8d96]">
      {/* Hidden but still focusable, so the checkbox keeps its keyboard behaviour. */}
      <input
        type="checkbox"
        role="switch"
        checked={checked}
        onChange={handleChange}
        className="peer absolute m-0 h-px w-px opacity-0"
      />
      <span
        aria-hidden="true"
        style={{ transition: 'background-color 200ms ease' }}
        className={`relative h-6 w-11 flex-none rounded-[12px] peer-focus-visible:[outline:2px_solid_#8f7635] peer-focus-visible:[outline-offset:2px] dark:peer-focus-visible:[outline-color:#c8a96a] ${
          checked
            ? 'bg-[#8f7635] dark:bg-[#c8a96a]'
            : 'bg-[rgba(111,109,100,0.85)] dark:bg-[rgba(138,141,150,0.8)]'
        }`}
      >
        <span
          style={thumbStyle}
          className="absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-white shadow-[0_1px_2px_rgba(0,0,0,0.25)] dark:bg-[#0e0f11]"
        />
      </span>
      <span>{label}</span>
    </label>
  );
}

More in Forms

Similar tags