Button
Le bouton TDS est conçu pour les parcours administratifs : lisible, contrasté, accessible au clavier et utilisable sans JavaScript.
Cinq variantes couvrent tous les niveaux de hiérarchie d’action.
| Variante | Usage | Quand l’utiliser |
|---|---|---|
primary | Action principale | Valider un formulaire, soumettre une demande |
secondary | Action secondaire | Retour, annuler, action alternative |
tertiary | Action discrète | Voir plus, liens d’interface secondaires |
danger | Action destructive | Supprimer, révoquer, action irréversible |
success | Confirmation positive | Approuver, accepter, finaliser |
Do / Don’t
✓ Faire
- Un seul bouton primary par section d’action
- Label verbe-actif : “Valider”, “Envoyer”, “Confirmer”
- Utiliser
dangeruniquement pour les actions irréversibles - Respecter la hiérarchie : primary → secondary → tertiary
✗ Éviter
- Deux boutons primary côte à côte
- Labels ambigus : “OK”, “Cliquer ici”, “Continuer”
- Créer de nouvelles variantes colorées hors de la palette
- Utiliser
dangerpour une action non destructive
Rendu avec le CSS réellement buildé de @tds-tchad/core — toutes les variantes, tailles et états.
Variantes
Aperçu des variantes (taille md)
Tailles
| Taille | Classe | Police | Padding | Min-height |
|---|---|---|---|---|
sm | tds-button--sm | 14px | 0.375rem 0.75rem | 44px |
md | tds-button--md | 16px | 0.75rem 1rem | 44px |
lg | tds-button--lg | 18px | 0.875rem 1.25rem | 44px |
États
| État | Classe / Attribut | Description |
|---|---|---|
| Normal | (aucun) | État par défaut |
| Hover | :hover (CSS) | Survol souris |
| Focus | :focus-visible (CSS) | Navigation clavier |
| Active | :active (CSS) | Clic en cours |
| Disabled | disabled + aria-disabled="true" | Bouton inactif |
| Loading | aria-busy="true" + texte | Traitement en cours |
Importation
/* CSS — requis pour les styles */@import "@tds-tchad/core/components/button/button.css";/* TypeScript — tokens et types */import { button } from '@tds-tchad/core/components/button';import type { ButtonVariant, ButtonSize } from '@tds-tchad/core/components/button';Exemples
Bouton primary standard
<button type="submit" class="tds-button tds-button--primary tds-button--md"> Soumettre la demande</button>Bouton avec icône
<button type="button" class="tds-button tds-button--primary tds-button--md"> <svg aria-hidden="true" focusable="false" width="16" height="16"> <use href="/icons/sprite.svg#icon-check" /> </svg> Valider</button>Bouton danger avec confirmation
<button type="button" class="tds-button tds-button--danger tds-button--md" aria-describedby="delete-warning"> Supprimer le dossier</button><p id="delete-warning" class="sr-only"> Cette action est irréversible. Le dossier sera définitivement supprimé.</p>Bouton désactivé
<button type="submit" class="tds-button tds-button--primary tds-button--md" disabled aria-disabled="true"> Soumettre (formulaire incomplet)</button>Bouton en état loading
<button type="submit" class="tds-button tds-button--primary tds-button--md" aria-busy="true" disabled> <span aria-hidden="true">Envoi en cours…</span> <span class="sr-only">Envoi en cours, veuillez patienter.</span></button>Lien stylisé en bouton
<!-- Préférer <button> ; utiliser <a> uniquement pour la navigation --><a href="/dossiers" class="tds-button tds-button--secondary tds-button--md" role="button"> Voir mes dossiers</a>Composant Button minimal
import '@tds-tchad/core/components/button/button.css';import type { ButtonVariant, ButtonSize } from '@tds-tchad/core/components/button';
interface ButtonProps { variant?: ButtonVariant; size?: ButtonSize; disabled?: boolean; loading?: boolean; type?: 'button' | 'submit' | 'reset'; onClick?: () => void; children: React.ReactNode;}
export function Button({ variant = 'primary', size = 'md', disabled = false, loading = false, type = 'button', onClick, children,}: ButtonProps) { const isDisabled = disabled || loading;
return ( <button type={type} className={`tds-button tds-button--${variant} tds-button--${size}`} disabled={isDisabled} aria-disabled={isDisabled || undefined} aria-busy={loading || undefined} onClick={onClick} > {children} </button> );}Usage
// Formulaire de soumission<Button type="submit" variant="primary" size="md"> Envoyer la demande</Button>
// Action destructive<Button variant="danger" onClick={handleDelete}> Supprimer le compte</Button>
// État loading<Button variant="primary" loading={isSubmitting}> {isSubmitting ? 'Envoi en cours…' : 'Soumettre'}</Button>
// Désactivé<Button variant="primary" disabled={!isFormValid}> Valider (remplissez tous les champs)</Button>Composant Button
<script setup lang="ts">import '@tds-tchad/core/components/button/button.css';import type { ButtonVariant, ButtonSize } from '@tds-tchad/core/components/button';
const props = withDefaults( defineProps<{ variant?: ButtonVariant; size?: ButtonSize; disabled?: boolean; loading?: boolean; type?: 'button' | 'submit' | 'reset'; }>(), { variant: 'primary', size: 'md', disabled: false, loading: false, type: 'button', });
const emit = defineEmits<{ click: [event: MouseEvent];}>();
const isDisabled = computed(() => props.disabled || props.loading);</script>
<template> <button :type="type" :class="`tds-button tds-button--${variant} tds-button--${size}`" :disabled="isDisabled" :aria-disabled="isDisabled || undefined" :aria-busy="loading || undefined" @click="emit('click', $event)" > <slot /> </button></template>Usage
<TdsButton type="submit" variant="primary"> Envoyer</TdsButton>
<TdsButton variant="danger" @click="handleDelete"> Supprimer</TdsButton>
<TdsButton :loading="isSubmitting" variant="primary"> {{ isSubmitting ? 'Envoi…' : 'Soumettre' }}</TdsButton>Contraste des variantes
| Variante | Fond | Texte | Ratio |
|---|---|---|---|
| primary | blue.500 (#0033A0) | blanc | 8.59:1 ✅ AAA |
| secondary | blanc | neutral.800 | 14.2:1 ✅ AAA |
| tertiary | transparent | neutral.800 | 14.2:1 ✅ AAA |
| danger | red.500 (#DA291C) | blanc | 5.1:1 ✅ AA |
| success | green.500 (#006B3C) | blanc | 7.2:1 ✅ AA |