Skip to content
design system
Thème d’affichage, actuellement Auto

molecule · stable · site, app, extension · since 2026-08

ThemeSwitch

Purpose

The choice of theme: automatic, light, dark. Following the system is a good default and not a sufficient answer; for whoever suffers from photophobia or visual fatigue, the choice is a reading condition. Three states rather than two, so that choosing does not mean giving up the system’s switch at sunset.

When to use, when not

Once per surface, in the header or the sidebar. A second instance on a page, as in a mobile menu, takes its own name.

Anatomy

  1. A fieldset with a visually hidden legend that names the group and says the current choice.
  2. Three labels, each wrapping a visually hidden radio and its word.

Props

Props of ThemeSwitch
NameTypeDefaultWhat it does
name?string'theme'The radio group's name. Two switches on one page each need their own, or the browser merges them into one group.
onchange?((theme: Theme) => void) | undefinedCalled with the choice once it is stored and applied: a surface that repaints something else with the theme (the extension's page furniture) hears it here.

States

Automatic, light or dark checked.

named

A second switch on the same page takes its own group name, or the browser merges the two.

Light
Thème d’affichage, actuellement Auto
Dark
Thème d’affichage, actuellement Auto
320 px, light
Thème d’affichage, actuellement Auto
320 px, dark
Thème d’affichage, actuellement Auto
216 px, light
Thème d’affichage, actuellement Auto
Forced colours, captured
ThemeSwitch, story named, as Chromium renders it with forced colours active

plain

The group reads the stored choice at mount; on the docs site it is whatever the reader chose.

Light
Thème d’affichage, actuellement Auto
Dark
Thème d’affichage, actuellement Auto
320 px, light
Thème d’affichage, actuellement Auto
320 px, dark
Thème d’affichage, actuellement Auto
216 px, light
Thème d’affichage, actuellement Auto
Forced colours, captured
ThemeSwitch, story plain, as Chromium renders it with forced colours active

Accessibility contract

  • Role and name: a radio group named “Thème d’affichage”; each radio named Auto, Clair or Sombre.
  • Keyboard: Tab enters on the checked radio, the arrows move the choice, nothing else.
  • Focus: shown on the visible label, since the radio is out of the visual field; never display: none, which would remove the radio from the tab order.
  • Forced colours: the checked option is drawn with a border, since a background fill is dropped.
  • The choice is read, stored and applied by theme/theme.ts, the same module on the three surfaces.

Content rules

The three French words: Auto, Clair, Sombre.

Do and don’t

  • Do keep it a radio group; a cycling button makes the user guess what comes next.
  • Do not hide the radios with display: none.

Examples

<ThemeSwitch />
<ThemeSwitch name="theme-mobile" />

Surfaces

  • Site: the header, and the mobile menu with its own name.
  • App: the lab sidebar.
  • Extension: the panel’s toggle cycles the same three choices through the same module.

Related

None.

Decisions

  • 2026-08: native radios, so the state is announced without a line of script.
  • 2026-09-24: reads and writes through the shared theme module.
  • 2026-09-24: renamed from ChoixTheme; the legend says “actuellement” with a comma, no dash.
  • 2026-09-27: onchange, called once the choice is stored and applied. The extension’s panel keeps the theme in a store that also tells the audited page, so its highlights repaint; the switch stored and applied on its own, and the page never heard of the change.

Criteria held by construction

  • 11.1, Chaque champ de formulaire a-t-il une étiquette ?
    Three native radios in a fieldset whose legend names the group; each option is a label.
  • 11.5, Dans chaque formulaire, les champs de même nature sont-ils regroupés, si nécessaire ?
    The three choices are grouped in a fieldset with a legend.
  • 10.7, Dans chaque page web, pour chaque élément recevant le focus, la prise de focus est-elle visible ?
    The radio stays in the tab order and the focus shows on its visible label.

Tokens it reads

  • Colour: --rl-action, --rl-ink, --rl-ink-soft, --rl-line-control, --rl-on-fill, --rl-sunken, --rl-focus, --rl-focus-offset, --rl-focus-width
  • Typography: --rl-weight-bold, --rl-text-xs
  • Layout: --rl-radius, --rl-border, --rl-border-strong