Atomes
52 primitives d’atomes — boutons, champs, badges, typographie — qui composent chaque molécule du système.
Les plus petites primitives d’interface. Chaque atome possède un élément DOM, ses jetons et son contrat d’accessibilité — il ne récupère jamais de données et ne connaît jamais les autres atomes.
Pourquoi les atomes
Les atomes sont les plus petites unités autonomes du système de design ePassLive — boutons, champs, badges, avatars, tags. Chaque atome possède exactement un élément DOM, ses jetons de design et son contrat d'accessibilité ; il ne récupère jamais de données et ne connaît jamais les autres atomes. Utilise un atome dès que le besoin d'interface se nomme en un seul mot — « un bouton », « un prix », « un statut ». Compose les atomes en molécules et en organismes plutôt que de les restyler surface par surface. Garantie du système de design : chaque atome est livré conforme WCAG 2.2 AA, thématisé par le même jeu de jetons en mode clair et sombre, et couvert par des tests unitaires avec assertions ARIA. Si un assemblage se répète sur trois surfaces ou plus, promeus-le en molécule — ne fork jamais l'atome.
Implémentés
Avatar
Circular user avatar with initials fallback and optional image. Sizes: sm (32px), md (40px), lg (56px), xl (80px).
Ouvrir le composantBadge
Numeric count badge for notification and nav counts. Count-based API (number or max+), never children. Five semantic variants on ADR-027 tint/fg pairs — WCAG 2.2 AA (≥4.5:1) in light and dark themes.
Ouvrir le composantBarcode
QR (ISO/IEC 18004) or Code-128 B (ISO/IEC 15417) symbol — SVG-rendered for crisp scaling. Rendered on every issued ticket and at order lookup via the storefront QrCode facade (ConfirmationView, OrderLookupForm). Decorative when paired with text; meaningful when sole identifier.
Ouvrir le composantButton
Primary interactive button — variants: primary (teal CTA), secondary (outlined), ghost (text-only), danger (destructive). Sizes: sm/md/lg all enforce WCAG 2.5.5 44px tap-min (var(--ep-tap-min)); size changes padding and font-size, not height.
Ouvrir le composantCaption
Small muted caption text (ep-xs, text-muted) for figure captions, helper lines and secondary annotations. Polymorphic via `as`.
Ouvrir le composantCheckbox
Tri-state checkbox with label. 18×18 box, 2px teal border, solid teal fill with a white check glyph when checked. Indeterminate state supported. Use for selections; use Switch for immediate on/off settings.
Ouvrir le composantSurface
The generic bordered, token-backed box that domain cards and panels compose. Use instead of hand-writing rounded/border/background utilities at the call site; carries no content structure of its own.
Ouvrir le composantChip
Selectable filter chip — multi-select group. Like a small Pill but with optional leading icon and selected/unselected visual states.
Ouvrir le composantColorSwatch
Color preview block — 24×24 rounded square with hex/RGB tooltip. Used in design system docs and theme editor.
Ouvrir le composantDivider
Horizontal 1px divider in --c-border-light. Used inside stat cards, table rows, side cards.
Ouvrir le composantIcon
Icon system with five atoms per ADR-022: PhosphorIcon (Admin-UI, 242 canonical names incl. 9 ADR-022-amend-01 EXTRAS + 25 Figma aliases, provenance in PHOSPHOR_ICON_SOURCES), VuesaxIcon (Storefront, 660 names, DS-ICONO-004), BrandIcon (~50 brands, DS-ICONO-005), FlagIcon (13 province flags, google/region-flags Public Domain), AlertIcon (variant-driven Phosphor wrapper — error/warning/info/success — for role=alert slots, ADR-026 + DS-ICONO-006b). ADR-021 size convention (7 sizes + stroke/LARGE_GRAPHIC/brand exceptions). Always aria-hidden unless the sole label. ICONO-ADOPT run (2026-08-17) migrated all dashboard/admin SVG to PhosphorIcon, all storefront public SVG to VuesaxIcon, Footer social letters to BrandIcon, and province flags to google/region-flags.
Ouvrir le composantIconButton
40×40 circular icon-only button. Used in header for notifications, settings, theme toggle. Dark variant in light mode (#1A2332 bg / white fg), neutral in dark mode.
Ouvrir le composantInput
Text input with label, helper, error, and disabled states. Focus indication is painted by the wrapper via `focus-within:ring-2 ring-ep-teal border-ep-teal`; the inner `<input>` carries `focus:outline-none` so the browser's default outline does not stack. Required for all forms. ADR-071: exactly one focus indicator per field group, owned by the chrome container — chromeless mode never self-rings by default; `focusRing="self"` is the opt-in for bare fields with no parent focus chrome. Every `ring-offset-2` carries `ring-offset-ep-bg`.
Ouvrir le composantInputOTP
Multi-digit OTP input. Auto-advance between digits, paste support.
Ouvrir le composantInputPhone
Phone number input with country code selector. Format validation.
Ouvrir le composantKbd
Keyboard key indicator — 20×20 with monospace font, 1px border, 4px radius. Used in shortcuts hints.
Ouvrir le composantLabel
Form control label with htmlFor binding and optional required marker (asterisk, aria-hidden, semantic-error color).
Ouvrir le composantLogo
Original ePassLive logo with 4 elements: QR Code (mode-adaptive), Code Scanner Frame (mode-adaptive), Teal 'e' lettermark (brand-locked), PSSLIVE wordmark (mode-adaptive). Theme-aware via --logo-fg token.
Ouvrir le composantPriceTag
Formatted price — locale-aware currency display. Sizes: sm/md/lg. Variants: default / strikethrough / from-prefix.
Ouvrir le composantRadio
Radio button for a radio group. Wrapped by RadioGroup which manages arrow-key navigation between siblings.
Ouvrir le composantSeasonPassBadge
Season-pass loyalty tier badge — tier-colored diamond + label pill (gold/silver/bronze/platinum). Describes WHO the holder is; distinct from CategoryPill (ticket tier) and StatusBadge (lifecycle state). Exported from the barrel; role=img with derived aria-label.
Ouvrir le composantSkeleton
Loading skeleton — radius matched to whatever it's skeletonizing. Use while Server Components fetch data.
Ouvrir le composantSelect
Native select with visible label, helper text, and error state. Focus indication painted by the wrapper (focus-within ring); custom chevron. aria-describedby wired to helper/error. WCAG 2.5.5 tap-min enforced by wrapper height.
Ouvrir le composantSpinner
Loading indicator — teal ring with rotating segment. Sizes: sm (16), md (24), lg (40). aria-label or aria-labelledby required when no visible label.
Ouvrir le composantSwitch
Toggle switch — 36×20 pill, teal when on, neutral when off. role='switch' with aria-checked.
Ouvrir le composantTag
Removable label chip — used in filter bars, multi-select displays, taxonomy. Has a × button with aria-label='Remove {label}'.
Ouvrir le composantTextarea
Multi-line text input with fixed rows (default 4) and resize-y — it does NOT auto-grow. Optional char counter, helper text, and error state. Focus indication is painted directly via `focus:ring-2 focus:ring-ep-teal focus:border-ep-teal`; `focus:outline-none` suppresses the browser's default outline so a single focus indicator is visible. Same label/error/required contract as Input. Note: the props array below is partial — showCounter, helperText, error, and required are documented in the interface string but not yet mirrored as props rows.
Ouvrir le composantLanguageToggle
Header language switcher. Shows the TARGET language token (e.g. "EN" while FR is active); when onChange is provided, toggles FR⇄EN. aria-label always announces the current language and the action so the single visible token stays unambiguous to assistive tech.
Ouvrir le composantNavLink
Primary-navigation anchor with a built-in active-state underline indicator. Bundles label + indicator (atom convention). Presentational: the consumer decides `active` (e.g. from the current route) so the atom stays framework-agnostic.
Ouvrir le composantSocialIconButton
Circular icon link for social profiles. Bundles the icon with its required accessible label so an icon-only control is never shipped without its text alternative. Opens in a new tab (target=_blank, rel=noopener noreferrer).
Ouvrir le composantBrandSurface
ADR-031 accent surface atom — one of the three valid accent contexts. Tinted variant (10% accent fill + 50% border, radius-lg) for light backgrounds; pill variant (solid surface-card fill + 50% border + shadow, radius-full) for surfaces over images/photos where bare tints vanish (§89.1). Attaches a brand hue to a stable identity.
Ouvrir le composantBrandRibbon
ADR-031 decorative 4-hue gradient strip (teal → indigo → amber → pink) — one of the three valid accent contexts. The bookend pattern: a 4px strip above the header and a matching strip at the top of the footer. Always aria-hidden + role=presentation; theme-stable (all four hues are non-swapping tokens).
Ouvrir le composantAccentUnderline
ADR-031 short decorative brand-accent underline (h-0.5 w-6 rounded-ep-full) for section headings — one of the three valid accent contexts. Signals the heading's stable identity (the FooterColumn pattern). Always aria-hidden; the heading carries the semantics.
Ouvrir le composantBody
Paragraph-level body text (text-ep-sm/base/lg scale, text-ep-text-body color, SECONDARY font slot by default). Renders a semantic <p>; polymorphic via as for span/div inline usage.
Ouvrir le composantH1
Level 1 heading for page titles.
Ouvrir le composantH2
Level 2 heading for major sections.
Ouvrir le composantH3
Level 3 heading for subsections.
Ouvrir le composantH4
Level 4 heading for nested sections.
Ouvrir le composantH5
Level 5 heading.
Ouvrir le composantH6
Level 6 heading.
Ouvrir le composantPre
Preformatted text block.
Ouvrir le composantOverline
Small uppercase label text.
Ouvrir le composantTextLink
Inline text link with variants.
Ouvrir le composantCode
Inline code formatting.
Ouvrir le composantBlockquote
Block-level quotation.
Ouvrir le composantHeading
Polymorphic heading component H1-H6.
Ouvrir le composantFormField
Label + control wrapper atom. Binds label htmlFor to the child control via cloneElement (injects id, aria-describedby, aria-invalid), renders required asterisk, hint paragraph, and role=alert error paragraph with AlertIcon fallback. Supports read-only display mode (label above rendered value, mono code option) and flex width slots for FormRow composition.
Ouvrir le composantFormFieldError
Standalone inline validation-error atom: renders the message in a role=alert paragraph with semantic-error color. Renders nothing when message is empty.
Ouvrir le composantPageSizeDropdown
Inline pagination size selector atom (DS-CORR-11-09). Borderless button trigger (current value + chevron) opening a popover listbox of page sizes. Designed for pagination footers ('Showing [8 v] out of 312'). Full keyboard support: Enter/Space opens, arrows navigate (wrapping), Escape closes, Home/End jump.
Ouvrir le composantStatusBadge
Semantic status badge with icon slot. Variants: success, warning, error, info, neutral, refunded. Locked icon mapping (Check/Clock/X/Info/Minus/RotateCcw). WCAG 1.4.1: label always required.
Ouvrir le composantTouchTargetEnforcer
A11y utility wrapper (DS-CORR-08-10) enforcing the 44×44px tap-target floor (WCAG 2.5.5). Wraps any interactive child (button/a/label) in an inline-flex span using the --ep-tap-min CSS variable via tapTargetStyle; negative margins compensate so the wrapper never expands the visual footprint — it is purely a hit-area expander.
Ouvrir le composantThemeToggle
Light/dark theme toggle button. Persists choice to localStorage (key per app) and swaps the html class. aria-pressed reflects the current theme.
Ouvrir le composant