molecule · stable · extension · since 2026-09
StatusToggle
Purpose
The three statuses an auditor gives a criterion, as one button each in a named group: the retained one says so with aria-pressed, and each button carries the symbol of core next to the letter. “Non testé” is not offered: it is the absence of an answer.
When to use, when not
Use it wherever a criterion is judged in place: the rows of the panel, a criterion form. Not for a wizard’s question, which is AnswerButtons with Oui and Non; not to display a status, which is StatusChip.
Anatomy
- The group, named “Statut du critère 1.1”.
- One button per status, the symbol hidden, the letter visible, the word in the name.
Props
| Name | Type | Default | What it does |
|---|---|---|---|
criterionId | string | The criterion's code, which names the group and each button: "Statut du critère 1.1". | |
value? | StatutDeCritere | undefined | The status retained; `NT` or absent leaves every button unpressed. | |
onchange | (status: ChosenStatus) => void | Called with the status pressed. Pressing the retained one calls it again; the caller decides whether that clears it. | |
statuses? | ChosenStatus[] | ['C', 'NC', 'NA'] | The statuses offered, in order. |
size? | 'sm' | 'md' | 'sm' | `sm` in a row of the panel, `md` in a form. |
hooks? | ((status: ChosenStatus) => DataHooks) | undefined | The `data-*` attributes of each button, from its status: what a click delegate or a walk reads. | |
class? | string | '' | Layout classes only. |
States
Nothing pressed yet, one pressed, a reduced set, the form size, and the buttons carrying a consumer’s hooks.
hooked
The extension answers the buttons with a click delegate: each carries its data-action and the criterion, and the markup is otherwise the same.
Light
Critère 8.2 : pour chaque page web, le code source généré est-il valide ?
Dark
Critère 8.2 : pour chaque page web, le code source généré est-il valide ?
320 px, light
Critère 8.2 : pour chaque page web, le code source généré est-il valide ?
320 px, dark
Critère 8.2 : pour chaque page web, le code source généré est-il valide ?
216 px, light
Critère 8.2 : pour chaque page web, le code source généré est-il valide ?
Forced colours, captured

medium
The size of a form, for a screen that holds one criterion.
Light
Critère 6.1 : chaque lien est-il explicite ?
Dark
Critère 6.1 : chaque lien est-il explicite ?
320 px, light
Critère 6.1 : chaque lien est-il explicite ?
320 px, dark
Critère 6.1 : chaque lien est-il explicite ?
216 px, light
Critère 6.1 : chaque lien est-il explicite ?
Forced colours, captured

pressed
Non conforme retained: the fill, the symbol and the letter say it together.
Light
Dark
320 px, light
320 px, dark
216 px, light
Forced colours, captured
twoOnly
A criterion that cannot be non applicable: the group offers what the caller lists.
Light
Dark
320 px, light
320 px, dark
216 px, light
Forced colours, captured
untested
No answer yet, under its criterion as in a row of the panel: every button unpressed. Press one; pressing it again calls the handler again and the story keeps it.
Light
Critère 1.1 : chaque image porteuse d’information a-t-elle une alternative textuelle ?
Dark
Critère 1.1 : chaque image porteuse d’information a-t-elle une alternative textuelle ?
320 px, light
Critère 1.1 : chaque image porteuse d’information a-t-elle une alternative textuelle ?
320 px, dark
Critère 1.1 : chaque image porteuse d’information a-t-elle une alternative textuelle ?
216 px, light
Critère 1.1 : chaque image porteuse d’information a-t-elle une alternative textuelle ?
Forced colours, captured

Accessibility contract
- Role and name: a
groupnamed for the criterion; each button named “NC, Non conforme, critère 1.1” witharia-pressed. - Keyboard, focus: Tab reaches each button; Enter and Space press it; the focus stays on the button pressed, so the row can redraw in place.
- Live regions: none; the pressed state is announced by the button itself. A row that also writes a note announces that elsewhere.
Content rules
French. The words are LIBELLES_DE_STATUT from core, never a copy; the shapes are the package’s status icons, drawn and hidden, never a text glyph, which would count in the visible label and be missing from the name. The group’s name is “Statut du critère” and the code.
Do and don’t
- Do give the criterion’s code, always: three hundred groups named “Statut” are one group.
- Do not add a fourth button for “non testé”; clearing an answer is a command of the row, if the product wants one.
- Do not colour the letter at rest; the fill is for the pressed state only.
- Do give
hookswhen a click delegate answers the buttons:hooks={() => ({ 'data-action': 'set-status', 'data-criterion-id': id })}. The component’s owndata-statusstays.
Examples
<StatusToggle criterionId={criterion.id} value={result?.status} onchange={(status) => setStatus(criterion.id, status)} /> Surfaces
- Extension: every criterion row of the panel.
Related
CriterionRow, StatusChip, AnswerButtons.
Decisions
- 2026-09-26: pressing the retained status calls the handler again rather than clearing it here: whether a second press clears the answer is the store’s rule, and the component does not keep a state of its own.
- 2026-09-27:
hookshangs a consumer’sdata-*attributes on each button, rather than the package naming the extension’s actions: the extension’s click delegate, its focus return and its walks readdata-action="set-status"and the criterion, and the web app reads nothing.DataHooksadmitsdata-*keys only, so no hook can change a name or a role.
Criteria held by construction
- 3.1, Dans chaque page web, l'information ne doit pas être donnée uniquement par la couleur. Cette règle est-elle respectée ?
The pressed status is told by aria-pressed, the symbol and the letter, and only then by the fill; the word is in the name. - 7.1, Chaque script est-il, si nécessaire, compatible avec les technologies d'assistance ?
Native buttons with aria-pressed: the pressed state is the one assistive technology already knows, in a group named for the criterion. - 11.9, Dans chaque formulaire, l'intitulé de chaque bouton est-il pertinent ?
The name of every button is explicit out of context: the letter, the word from core and the criterion.
Tokens it reads
- Colour:
--rl-c,--rl-hover,--rl-ink,--rl-ink-soft,--rl-line-control,--rl-line-strong,--rl-na,--rl-nc,--rl-on-fill,--rl-surface - Typography:
--rl-weight-bold,--rl-text-base,--rl-text-sm - Spacing:
--rl-space-1,--rl-space-1-5,--rl-space-3,--rl-space-half,--rl-target-min - Layout:
--rl-radius,--rl-border