Button
Déclenche une action utilisateur. Quatre variantes, chacune avec une hiérarchie et un usage précis. La variante critical porte des règles comportementales spéciales pour les actions irréversibles.
Triggers a user action. Four variants, each with a precise hierarchy and use case. The critical variant carries special behavioral rules for irreversible actions.
VariantesVariants
IcônesIcons
Approche hybride : propriété (Figma, React, tous frameworks) ou slot (composition avancée). Le contenu slotté a toujours la priorité sur la propriété. Hybrid approach: property (Figma, React, all frameworks) or slot (advanced composition). Slotted content always takes priority over the property.
label obligatoire (WCAG 1.1.1)Icon-only — label required (WCAG 1.1.1)
<!-- Propriété icon — Figma Code Connect, React et tous les frameworks -->
<agtc-button icon="plus">Ajouter un élémentAdd item</agtc-button>
<agtc-button variant="secondary" icon-suffix="arrow-right">ContinuerContinue</agtc-button>
<!-- Icon-only — label="" obligatoire -->
<agtc-button icon-only icon="x" label="Fermer le panneauClose panel"></agtc-button>
<!-- Slot — composition avancée, SVG custom -->
<agtc-button>
<agtc-icon slot="prefix" name="plus"></agtc-icon>
Ajouter un élémentAdd item
</agtc-button>
Règles absoluesAbsolute rules
- Maximum 1 bouton
primarypar section ou formulaireMaximum 1primarybutton per section or form - Toujours un libellé explicite — jamais "OK" ou "Confirmer" seulAlways an explicit label — never "OK" or "Confirm" alone
- Le bouton
criticalDOIT déclencher un pattern de confirmationThecriticalbutton MUST trigger a confirmation pattern - Toujours un
:focus-visiblevisible —outline: 2px solid var(--agtc-semantic-color-border-focus)Always a visible:focus-visible—outline: 2px solid var(--agtc-semantic-color-border-focus) - Jamais deux boutons
primarycôte à côteNever twoprimarybuttons side by side - Jamais de couleur ou espacement en durNever hardcoded colors or spacing
- Jamais de variante inventée hors de
component.jsonNever an invented variant outsidecomponent.json
Tokens de composantComponent tokens
| Token CSS | Référence sémantiqueSemantic reference | Valeur résolueResolved value |
|---|---|---|
--agtc-component-button-primary-background | semantic.color.action.primary | #007a68 |
--agtc-component-button-primary-background-hover | semantic.color.action.primary-hover | #0d3d38 |
--agtc-component-button-primary-background-disabled | semantic.color.action.primary-disabled | #d9d9d9 |
--agtc-component-button-primary-text | semantic.color.text.on-action | #ffffff |
--agtc-component-button-primary-padding-x | semantic.space.control.padding-x | 16px |
--agtc-component-button-primary-padding-y | semantic.space.control.padding-y | 8px |
--agtc-component-button-primary-radius | semantic.radius.control | 6px |
--agtc-component-button-critical-background | semantic.color.feedback.danger | #ce2c31 |
--agtc-component-button-secondary-text | semantic.color.action.primary | #007a68 |
--agtc-component-button-secondary-border | semantic.color.action.primary | #007a68 |
--agtc-component-button-ghost-text | semantic.color.action.primary | #007a68 |
AccessibilitéAccessibility
- Contraste minimum 4.5:1 sur fond blanc (WCAG AA)Minimum contrast 4.5:1 on white background (WCAG AA)
- Navigation clavier complète — Tab, Enter, SpaceFull keyboard navigation — Tab, Enter, Space
- Focus visible :
outline: 2px solid var(--agtc-semantic-color-border-focus); outline-offset: 2pxVisible focus:outline: 2px solid var(--agtc-semantic-color-border-focus); outline-offset: 2px - Pour les boutons icône seul :
aria-labelobligatoireFor icon-only buttons:aria-labelrequired - État
loading:aria-busy="true"+ largeur préservéeloadingstate:aria-busy="true"+ width preserved - État
disabled:aria-disabled="true"oudisableddisabledstate:aria-disabled="true"ordisabled
Règles spéciales — variante criticalSpecial rules — critical variant
Token component.button.critical.$metadata.requires-confirmation = true. Avant d'utiliser cette variante, vérifier :Before using this variant, verify:
- Le pattern de confirmation existe dans l'interface (modale, popconfirm)The confirmation pattern exists in the UI (modal, popconfirm)
- Le libellé décrit l'action — ex: "Supprimer définitivement le dossier"The label describes the action — e.g. "Delete folder permanently"
- Le contraste est ≥ 4.5:1 sur fond blancContrast is ≥ 4.5:1 on white background
- L'agent escalade à un humain si le caractère irréversible de l'action n'est pas certainThe agent escalates to a human if the irreversibility of the action is uncertain
Compatibilité frameworksFramework compatibility
| Framework | icon="..." | slot="prefix" | Figma Code Connect |
|---|---|---|---|
| HTML natif | ✅ | ✅ | — |
| ✅ | ✅ | ✅ | |
| ✅ | ⚠️ via refvia ref | ✅ | |
| ✅ | ✅ | ✅ | |
| ✅ | ✅ | ✅ | |
| ✅ | ✅ | ✅ |
Implémentation — Lit Web ComponentImplementation — Lit Web Component
import { LitElement, html, css } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
// agtc-icon doit être enregistré par le consommateur pour les propriétés icon/icon-suffix
// import './agtc-icon.js';
class AgtcButton extends LitElement {
static properties = {
variant: { type: String, reflect: true }, // 'primary'|'secondary'|'ghost'|'critical'
disabled: { type: Boolean, reflect: true },
loading: { type: Boolean, reflect: true },
iconOnly: { type: Boolean, reflect: true, attribute: 'icon-only' },
icon: { type: String }, // nom d'icône Lucide (prefix)
iconSuffix: { type: String, attribute: 'icon-suffix' }, // nom d'icône (suffix)
label: { type: String }, // aria-label — obligatoire pour icon-only
loadingLabel: { type: String, attribute: 'loading-label' },
};
render() {
const busy = this.loading;
return html`
<button
class="${[this.variant, busy ? 'loading' : '', this.iconOnly ? 'icon-only' : ''].filter(Boolean).join(' ')}"
?disabled="${this.disabled || busy}"
aria-busy="${busy}"
aria-label="${ifDefined(this.label ? (busy ? this.loadingLabel : this.label) : undefined)}"
>
<span class="spinner" aria-hidden="true"></span>
<span class="content">
<slot name="prefix">
${this.icon ? html`<agtc-icon name="${this.icon}" size="control"></agtc-icon>` : ''}
</slot>
<slot></slot>
<slot name="suffix">
${this.iconSuffix ? html`<agtc-icon name="${this.iconSuffix}" size="control"></agtc-icon>` : ''}
</slot>
</span>
</button>
`;
}
}
customElements.define('agtc-button', AgtcButton);
DOs et DON'TsDOs and DON'Ts
À faireDo
- Libellé explicite décrivant l'action (« Supprimer définitivement le dossier »)Explicit label describing the action ("Delete folder permanently")
- Maximum 1 bouton
primarypar section ou formulaireMaximum 1primarybutton per section or form - Toujours un
:focus-visiblevisible pour la navigation clavierAlways a visible:focus-visiblefor keyboard navigation - État
loadingavecaria-busy="true"pour les actions asynchronesloadingstate witharia-busy="true"for async actions - Pattern de confirmation obligatoire avant chaque action
criticalMandatory confirmation pattern before eachcriticalaction
À éviterDon't
- Libellé vague : « OK », « Confirmer », « Valider » seulVague label: "OK", "Confirm", "Submit" alone
- Deux boutons
primarycôte à côte dans le même formulaireTwoprimarybuttons side by side in the same form - Couleurs ou espacements en dur (
style="background:red")Hardcoded colors or spacing (style="background:red") - Variantes inventées hors de
tokens/component.jsonInvented variants outsidetokens/component.json - Bouton
criticalsans pattern de confirmationcriticalbutton without a confirmation pattern
Anti-patternsAnti-patterns
| MauvaisBad | PourquoiWhy |
|---|---|
<button style="background:red">Supprimer</button> | Valeur en dur, variante non reconnue, pas de tokenHardcoded value, unrecognized variant, no token |
<agtc-button variant="critical">OK</agtc-button> | Libellé non explicite pour une action critiqueNon-explicit label for a critical action |
Deux variant="primary" dans le même formulaireTwo variant="primary" in the same form | Hiérarchie cassée — perte de clarté UXBroken hierarchy — loss of UX clarity |
<agtc-button variant="danger"> | Variante inexistante — escalader, demander la variante correcteNon-existent variant — escalate, ask for the correct variant |
UX Patterns Reference
Patterns approved via the
ux-pattern-reviewworkflow (ADR-036). Decision: all approved.
| Pattern | Source | Applied | Justification |
|---|---|---|---|
| A single clear primary action per context | IxDF — clear primary action | ✅ | Readable action hierarchy |
Explicit confirmation for destructive action (critical) | NN/g — error prevention | ✅ | requires-confirmation |
Width preserved during loading | Smashing | ✅ | No layout jump |
Never disable without indicating why (prefer a motivated disabled over hiding the action) | Smashing — hidden vs disabled | ✅ | A silent disabled is an accessibility anti-pattern — provide help text/tooltip explaining the block |
| Label describing the consequence, not "OK" | NN/g | ✅ | Explicit label |