← Back to UI screens

Live: try it with the mouse and the keyboard (Tab, arrows, Escape).

ScreenshotToggle switch component — web, monochrome style
Theme

Toggle switch component — web, monochrome style

Toggle switch UI component for websites and web apps, shown in Fernway, a fictional productivity product. Shows a list of on/off settings with labels and hints, switches on and off, a disabled switch, and every state (default, hover, focus-visible, on, disabled). Monochrome style: pure greyscale, Geist, black primary actions and flat surfaces. Comes with copyable HTML, CSS and a few lines of plain JavaScript (keyboard support and ARIA per the WAI-ARIA Authoring Practices), a live demo, and a DESIGN.md with light and dark colour tokens.

Open live HTML ↗ Download DESIGN.md
Pattern
Toggle switch
Device
Web
Style
Monochrome
Product (fictional)
Fernway
Category
Productivity

Spec

Colours (light)
background #ffffff · surface #fafafa · text #111111 · muted #666666 · primary #111111 · accent #444444
Colours (dark)
background #0a0a0a · surface #161616 · text #f2f2f2 · muted #a0a0a0 · primary #f2f2f2 · accent #c8c8c8
Fonts
Geist (headings and body), JetBrains Mono (code) · Google Fonts, under their own licences
Light and dark
Both included; follows the system setting
ARIA pattern
Switch (WAI-ARIA Authoring Practices)
Keyboard
Space or Enter flips the switch
States
default, hover, focus-visible, selected, disabled
toggle-switchwebproductivitytogglelist

Code

Paste the HTML where the component goes, the CSS into your stylesheet and the script before </body>. The tokens block holds the light and dark colours; swap in your own.

HTML
<ul class="mgd-switches" aria-label="Notification settings">
  <li><span><span class="mgd-switches__label" id="sw-digest">Weekly email digest</span><span class="mgd-switches__hint" id="sw-digest-hint">A Monday summary of what changed in your projects.</span></span>
    <button class="mgd-switch" type="button" role="switch" aria-checked="true" aria-labelledby="sw-digest" aria-describedby="sw-digest-hint"><span class="mgd-switch__thumb"></span></button></li>
  <li><span><span class="mgd-switches__label" id="sw-desktop">Desktop notifications</span><span class="mgd-switches__hint" id="sw-desktop-hint">Pop-ups while Fernway is open in a browser tab.</span></span>
    <button class="mgd-switch" type="button" role="switch" aria-checked="false" aria-labelledby="sw-desktop" aria-describedby="sw-desktop-hint"><span class="mgd-switch__thumb"></span></button></li>
  <li><span><span class="mgd-switches__label" id="sw-mentions">Only when I'm mentioned</span><span class="mgd-switches__hint" id="sw-mentions-hint">Mute everything except @mentions and direct replies.</span></span>
    <button class="mgd-switch" type="button" role="switch" aria-checked="true" aria-labelledby="sw-mentions" aria-describedby="sw-mentions-hint"><span class="mgd-switch__thumb"></span></button></li>
  <li><span><span class="mgd-switches__label" id="sw-sms">Text message alerts</span><span class="mgd-switches__hint" id="sw-sms-hint">Add a phone number in your profile first.</span></span>
    <button class="mgd-switch" type="button" role="switch" aria-checked="false" aria-labelledby="sw-sms" aria-describedby="sw-sms-hint" disabled><span class="mgd-switch__thumb"></span></button></li>
</ul>
CSS
/* Tokens (light + dark) */
:root{--bg:#ffffff;--surface:#fafafa;--border:#e4e4e4;--text:#111111;--muted:#666666;--primary:#111111;--on-primary:#ffffff;--accent:#444444;--font-h:"Geist",Georgia,serif;--font-b:"Geist",system-ui,sans-serif;--hw:600;
--c-bw:1px;--c-line:var(--border);--c-r:6px;--c-pill:6px;--c-sh:none;--c-pop:0 10px 28px rgb(0 0 0 / .16);--c-tt:none;--c-ls:0;--c-fw:500;--c-fs:14px;--c-ring:2px solid var(--text);--c-ind:2px;color-scheme:light}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--bg:#0a0a0a;--surface:#161616;--border:#2c2c2c;--text:#f2f2f2;--muted:#a0a0a0;--primary:#f2f2f2;--on-primary:#0a0a0a;--accent:#c8c8c8;color-scheme:dark}
}
:root[data-theme="dark"]{--bg:#0a0a0a;--surface:#161616;--border:#2c2c2c;--text:#f2f2f2;--muted:#a0a0a0;--primary:#f2f2f2;--on-primary:#0a0a0a;--accent:#c8c8c8;color-scheme:dark}

/* Component */
.mgd-sr{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.mgd-switches{list-style:none;margin:0;padding:0;max-width:640px;border-top:1px solid var(--border)}
.mgd-switches li{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:16px 2px;border-bottom:1px solid var(--border)}
.mgd-switches__label{display:block;font:600 15px/1.35 var(--font-b);text-transform:var(--c-tt);letter-spacing:var(--c-ls)}
.mgd-switches__hint{display:block;margin-top:2px;color:var(--muted);font-size:13px}
.mgd-switch{flex:none;position:relative;width:48px;height:28px;padding:0;border:1.5px solid var(--muted);border-radius:999px;background:color-mix(in oklab,var(--muted) 22%,var(--bg));cursor:pointer;transition:background-color .14s,border-color .14s}
.mgd-switch__thumb{position:absolute;top:50%;left:3px;width:20px;height:20px;margin-top:-10px;border-radius:50%;background:var(--muted);box-shadow:none;transition:transform .14s,background-color .14s}
.mgd-switch:hover,.mgd-switch.is-hover{background:color-mix(in oklab,var(--muted) 34%,var(--bg))}
.mgd-switch:focus-visible,.mgd-switch.is-focus{outline:var(--c-ring);outline-offset:3px}
.mgd-switch[aria-checked="true"],.mgd-switch.is-on{background:var(--primary);border-color:var(--primary)}
.mgd-switch[aria-checked="true"] .mgd-switch__thumb,.mgd-switch.is-on .mgd-switch__thumb{transform:translateX(20px);background:var(--on-primary)}
.mgd-switch:disabled,.mgd-switch.is-off{opacity:.45;cursor:not-allowed}
@media (forced-colors:active){.mgd-switch[aria-checked="true"] .mgd-switch__thumb{background:Highlight}}
@media (prefers-reduced-motion:reduce){.mgd-switch,.mgd-switch *{transition:none!important;animation-duration:2.4s!important}}
JavaScript
document.querySelectorAll(".mgd-switch").forEach(function (sw) {
  sw.addEventListener("click", function () { sw.setAttribute("aria-checked", sw.getAttribute("aria-checked") !== "true"); });
});

DESIGN.md

Component section (states, ARIA, keyboard)
## Component: Toggle switch

On and off settings that apply straight away, each with a visible label and a hint.

- **Pattern:** WAI-ARIA Authoring Practices, Switch (https://www.w3.org/WAI/ARIA/apg/patterns/switch/)
- **Roles and attributes:** Each switch is a <button role="switch"> with aria-checked, named by its visible label (aria-labelledby) and described by its hint (aria-describedby); a disabled switch uses the disabled attribute.
- **States drawn:** default, hover, focus-visible, selected, disabled
- **Focus:** a visible `:focus-visible` outline (2px solid text), never removed
- **Style knobs (monochrome):** border 1px, corners 6px, shadow none, labels sentence case
- **Motion:** transitions are short (≤160ms) and switched off under `prefers-reduced-motion: reduce`
- **Code:** HTML + CSS + a few lines of plain JavaScript (no libraries); colours come only from the tokens above, so light and dark both work

### Keyboard
- **Tab:** move between switches
- **Space / Enter:** turn the focused switch on or off

### Licence
Original Made Good Designs code: free to use and adapt in any project, including commercial ones, with no credit needed. Fonts are Google Fonts under their own licences.
AI

Build this with your AI

Fonts: Geist (Google Fonts)

Writing about this component?

More toggle switch components

Toggle switch component — web, minimal (Fernway)
web · minimal
Toggle switch component — web, editorial (Fernway)
web · editorial
Toggle switch component — web, brutalist (Fernway)
web · brutalist
Toggle switch component — web, luxury (Fernway)
web · luxury
Toggle switch component — web, playful (Fernway)
web · playful
Toggle switch component — web, corporate (Fernway)
web · corporate
Toggle switch component — web, retro (Fernway)
web · retro
Toggle switch component — mobile, monochrome (Fernway)
mobile · monochrome
Building with an AI coding agent? Every screen here is also in the free Made Good Designs MCP server: ask Claude, Cursor or ChatGPT to search_ui_screens (e.g. “billing settings, editorial style”), get_ui_flow for a whole journey, and get_ui_screen_code to pull the HTML and DESIGN.md straight into your project.

Save to board