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

molecule · stable · app · since 2026-09

FilterGroup

Purpose

A row of filters that apply the moment they are pressed: a group named by a visible label, one button per filter with aria-pressed, several pressed at once or one alone when exclusive. No form, no “Appliquer”; the page says the count through its live region.

When to use, when not

Use it above a list for two to six filters the user sees at once. Use a RadioGroup when the filters are part of a form submitted later, a Select when there are more than six. Not for navigation between pages, which is a list of links.

Anatomy

  1. The visible label.
  2. The buttons, each with its word and its count when given.

Props

Props of FilterGroup
NameTypeDefaultWhat it does
labelstringThe visible label that names the group: "Statut", "Niveau".
filtersFilter[]The filters, in order. With `exclusive`, the first one is the one that shows everything.
selected?string[][]The values pressed; bindable.
exclusive?booleanfalseOne filter at a time, and one always pressed.
onchange?(selected: string[]) => voidCalled with the values pressed after each press.
class?string''Layout classes only.

States

Exclusive with “Tous” first, and several at once.

exclusive

One filter at a time, "Tous" first: pressing the pressed one changes nothing, so the list is never filtered by nothing.

Light
Statut
Dark
Statut
320 px, light
Statut
320 px, dark
Statut
216 px, light
Statut
Forced colours, captured
FilterGroup, story exclusive, as Chromium renders it with forced colours active

several

Several filters at once, none pressed at first; a press toggles, and the count is said by the page.

Light
Thématiques
Dark
Thématiques
320 px, light
Thématiques
320 px, dark
Thématiques
216 px, light
Thématiques
Forced colours, captured
FilterGroup, story several, as Chromium renders it with forced colours active

Accessibility contract

  • Role and name: a group named by the label through aria-labelledby; each button named by its word, with aria-pressed.
  • Keyboard, focus: Tab reaches each button; Enter and Space press it; the focus never moves on a press.
  • Live regions: none of the group’s. The page says the count of the filtered list through LiveRegion, present from the first render.

Content rules

French. The label is a noun (“Statut”, “Thématiques”); the filters are nouns or participles in the plural (“Terminés”, “Brouillons”); the first exclusive filter is “Tous”.

Do and don’t

  • Do announce the count after a press, in a sentence: “5 audits affichés”.
  • Do list “Tous” first when exclusive, so the list is never filtered by nothing.
  • Do not move the focus to the list on a press; the user is still choosing.

Examples

<FilterGroup label="Statut" filters={STATUSES} exclusive bind:selected={status} onchange={refilter} />
<LiveRegion message={count} visible />

Surfaces

  • App: the audits list, the users list.

Related

RadioGroup, Select, LiveRegion, Chip.

Decisions

  • 2026-09-26: buttons with aria-pressed and not radios: the filters apply at once, and a radio group promises a form.
  • 2026-09-26: an exclusive group refuses to unpress its last filter: a list filtered by nothing is the whole list, which “Tous” already says.

Criteria held by construction

  • 7.1, Chaque script est-il, si nécessaire, compatible avec les technologies d'assistance ?
    Native buttons with aria-pressed in a group named by its visible label: the state and the group are the ones assistive technology knows.
  • 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 ?
    A pressed filter is told by aria-pressed and the fill with the bold, not by a hue on an outline.
  • 11.1, Chaque champ de formulaire a-t-il une étiquette ?
    The group's label is visible and tied by aria-labelledby, so the filters are heard as 'Statut, groupe'.

Tokens it reads

  • Colour: --rl-hover, --rl-ink, --rl-line-control, --rl-line-strong, --rl-on-fill
  • Typography: --rl-weight-bold, --rl-text-sm, --rl-text-xs
  • Spacing: --rl-space-1, --rl-space-1-5, --rl-space-2, --rl-space-3, --rl-target-min
  • Layout: --rl-radius, --rl-border

Seen in patterns