Demo

The switch in the header of this page is the live demo. Try it with the keyboard: Tab to it, arrow keys choose.

Why it is accessible

Dark mode isn't just aesthetics: for people with light sensitivity or migraines, it is accessibility. This switch has three states, so rather than being a button that has to invent its own semantics, it is a plain group of radio buttons (fieldset, legend and three input type="radio"). The browser itself handles the grouping, the arrow-key movement and the “selected” state.

The choice is stored in the browser without cookies and applied before the page's first render, so nothing flashes. A status message announces the change: “Appearance: dark”. Every colour on the website is defined once for both modes, and in both it meets a contrast of 4.5:1 for text and 3:1 for controls.

Test it yourself

Keyboard

  • Tab to the switch in the header (the current choice is focused); and change the appearance immediately.

Screen reader

  • The group is announced as “Appearance”, each option as a radio button named Light, Dark or System, and after the change you hear a status message.

Zoom and reflow

  • The switch has three targets sized 44×44px, and at 400% zoom it moves onto its own line in the header.

Without JavaScript

The switch isn't shown, and the operating system's setting applies via prefers-color-scheme. Both appearances therefore remain available.

Code to copy

<ad-theme-toggle data-label="Appearance" data-light="Light" data-dark="Dark" data-system="System" data-announce="Appearance: {mode}"></ad-theme-toggle>
<script src="/assets/js/theme-init.js"></script>
<link rel="stylesheet" href="/assets/js/components/ad-theme-toggle/ad-theme-toggle.css">
<script type="module" src="/assets/js/components/ad-theme-toggle/ad-theme-toggle.js"></script>