Door

No dependencies
Code format
React + Tailwind
const css = `
  .toggle-door { position: relative; display: inline-flex; align-items: center; gap: 14px; color: light-dark(#42454c, #e5e6e9); font-size: 14px; cursor: pointer; user-select: none; }
  .toggle-door__input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }
  .toggle-door__scene { position: relative; flex: none; }
  .toggle-door__input:focus-visible + .toggle-door__scene { outline: 2px solid light-dark(#50535b, #c6c8cd); outline-offset: 4px; border-radius: 8px; }
  .toggle-door__scene { width: 50px; height: 64px; perspective: 200px; }
  .toggle-door__frame { position: absolute; left: 6px; right: 6px; top: 2px; bottom: 6px; border-radius: 3px 3px 0 0; background: light-dark(#fbfcfd, #121417); box-shadow: 0 0 0 3px light-dark(#cbced3, #393c41); overflow: visible; }
  /* Light from inside: a glow in the doorway and a pool spilling across the floor. */
  .toggle-door__glow { position: absolute; inset: 0; background: linear-gradient(color-mix(in oklab, light-dark(#373a40, #f1f2f3) 55%, transparent), color-mix(in oklab, light-dark(#373a40, #f1f2f3) 25%, transparent)); opacity: 0; transition: opacity 0.4s; }
  .toggle-door__spill { position: absolute; left: 4px; right: -10px; bottom: -6px; height: 8px; background: color-mix(in oklab, light-dark(#373a40, #f1f2f3) 30%, transparent); clip-path: polygon(6px 0, calc(100% - 14px) 0, 100% 100%, 0 100%); opacity: 0; transition: opacity 0.4s; }
  .toggle-door__door { position: absolute; inset: 0; border-radius: 2px 2px 0 0; background: linear-gradient(90deg, light-dark(#6d7179, #7d8087), light-dark(#cbced3, #393c41)); box-shadow: inset 0 0 0 3px light-dark(#6d7179, #7d8087), inset 0 0 0 4px light-dark(#dbdde1, #2e3035); transform-origin: 0 50%; transition: transform 0.6s cubic-bezier(0.3, 1.2, 0.5, 1); }
  .toggle-door__door::before { content: ''; position: absolute; left: 7px; right: 7px; top: 7px; height: 18px; box-shadow: inset 0 0 0 1px light-dark(#dbdde1, #2e3035); }
  .toggle-door__knob { position: absolute; right: 5px; top: 30px; width: 4px; height: 4px; border-radius: 50%; background: light-dark(#42454c, #e5e6e9); }
  .toggle-door__floor { position: absolute; left: 0; right: 0; bottom: 4px; height: 2px; background: light-dark(#cbced3, #393c41); }
  .toggle-door__input:checked + .toggle-door__scene .toggle-door__door { transform: rotateY(-68deg); }
  .toggle-door__input:checked + .toggle-door__scene .toggle-door__glow, .toggle-door__input:checked + .toggle-door__scene .toggle-door__spill { opacity: 1; }
  @media (prefers-reduced-motion: reduce) {
    .toggle-door * { transition: none !important; }
  }
`;

export function DoorToggle() {
  return (
    <>
      <style>
        {css}
      </style>
      <label className="toggle-door">
        <input className="toggle-door__input" type="checkbox" role="switch" />
        <span className="toggle-door__scene" aria-hidden="true">
          <span className="toggle-door__frame">
            <span className="toggle-door__glow" />
            <span className="toggle-door__door">
              <span className="toggle-door__knob" />
            </span>
          </span>
          <span className="toggle-door__floor" />
          <span className="toggle-door__spill" />
        </span>
        Guest access
      </label>
    </>
  );
}

Free to use in any project, commercial included. MIT-0, no attribution required. Licence

Install with shadcn

npx shadcn@latest add @movin/toggle-door
Source on GitHub

About this component

A guest access switch drawn as a door: switching on, it swings open in 3D on its hinge and light spills out from the doorway across the floor.

Dependencies
None
Difficulty
Beginner
Triggers
click, state change, 3d, glow
Techniques
3d transform, perspective, css transition, clip path
Reduced motion
Respected
Theme
Light and dark (follows your page's color-scheme)

A native checkbox with role="switch" inside a <label>, so Space toggles it and screen readers announce a switch; the visible label names it and :focus-visible on the input outlines the visual. Under prefers-reduced-motion the door opens instantly.

More toggles

See all
Earbuds
Flag
Lid
Match