# DSBJ - Design Système du Bénin - Documentation complète
> Le Design Système du Bénin (DSBJ) est le système de design officiel de la République du Bénin. Il fournit 53 composants HTML/CSS/JS réutilisables, accessibles (WCAG 2.1 AA), avec le préfixe CSS `bj-` et les variables CSS `--bj-*`. Package npm : `@flrxnt/dsbj`.
## Informations générales
- **Package** : `@flrxnt/dsbj` v1.0.0
- **Installation** : `npm install @flrxnt/dsbj` ou `bun add @flrxnt/dsbj`
- **CDN** : `https://unpkg.com/@flrxnt/dsbj@1.0.0/dist/dsbj.css` + `dsbj.umd.js`
- **Imports** : `import '@flrxnt/dsbj'` (auto-init) ou `import '@flrxnt/dsbj/css'` (CSS seul) ou `@use '@flrxnt/dsbj/scss'` (SCSS)
- **Préfixe CSS** : toutes les classes utilisent `bj-`, toutes les variables `--bj-*`
- **Thème sombre** : `` ou automatique via `prefers-color-scheme`
- **Polices** : Open Sans (400, 500, 600, 700) pour le corps, Spectral (400, 600) pour titres éditoriaux
- **Icônes** : Remix Icon 4.1 (`ri-*`), toujours avec `aria-hidden="true"` sur icônes décoratives
- **Grille** : 12 colonnes responsive avec `bj-container`, `bj-grid-row`, `bj-col-{1-12}`, `bj-col-md-{1-12}`, `bj-col-lg-{1-12}`
- **Accessibilité** : WCAG 2.1 AA, navigation clavier, attributs ARIA sur tous les composants interactifs, `:focus-visible`, skip links
## Structure HTML de base
```html
Titre - Mon service - République du Bénin
...
```
---
## Fondamentaux
### Couleurs
Tokens de couleur principaux (variables CSS) :
- `--bj-color-vert-benin-main-491` : Vert Bénin principal (#008751)
- `--bj-color-jaune-benin-main-491` : Jaune Bénin (#FCD116)
- `--bj-color-rouge-benin-main-491` : Rouge Bénin (#E8112D)
- `--bj-action-high` : Couleur d'action principale (vert Bénin)
- `--bj-text-default` : Texte par défaut
- `--bj-text-alt` : Texte secondaire
- `--bj-bg-default` : Fond par défaut
- `--bj-bg-alt` : Fond alternatif
- `--bj-border-default` : Bordure par défaut
- `--bj-border-subtle` : Bordure subtile
- `--bj-success`, `--bj-warning`, `--bj-error`, `--bj-info` : Couleurs sémantiques
### Typographie
- Display : `bj-display-xs` à `bj-display-xl`
- Titres : `bj-h1` à `bj-h6`
- Texte : `bj-text-xs`, `bj-text-sm`, `bj-text-md`, `bj-text-lg`, `bj-text-xl`
- Variables : `--bj-fs-xs` à `--bj-fs-xl`, `--bj-fw-regular` (400), `--bj-fw-medium` (500), `--bj-fw-semibold` (600), `--bj-fw-bold` (700)
### Espacement
- Variables : `--bj-spacing-1v` (0.25rem) à `--bj-spacing-16v` (4rem)
- Classes marges : `bj-m-{1v..16v}`, `bj-mt-*`, `bj-mb-*`, `bj-ml-*`, `bj-mr-*`, `bj-mx-*`, `bj-my-*`
- Classes padding : `bj-p-{1v..16v}`, `bj-pt-*`, `bj-pb-*`, `bj-pl-*`, `bj-pr-*`, `bj-px-*`, `bj-py-*`
### Grille
```html
```
Modificateurs : `bj-grid-row--gutters`, `bj-grid-row--middle`, `bj-grid-row--center`
### Ombres
- `--bj-shadow-sm`, `--bj-shadow-md`, `--bj-shadow-lg`, `--bj-shadow-xl`
- Classes : `bj-shadow-sm` à `bj-shadow-xl`
---
## Composants
### Header (En-tête de page)
Classes : `bj-header`, `bj-header__body`, `bj-header__brand`, `bj-header__service`, `bj-header__service-title`, `bj-header__service-tagline`, `bj-header__tools`, `bj-header__tools-link`, `bj-header__menu-btn`, `bj-header__nav`, `bj-header__nav-list`, `bj-header__nav-item`, `bj-header__nav-link`, `bj-header__nav-link--active`
ARIA : `role="banner"` sur header, `role="navigation"` + `aria-label` sur nav, `aria-controls` + `aria-expanded` sur menu mobile, `aria-current="page"` sur lien actif
JS : `data-bj-header-menu` sur le bouton menu
```html
```
### Footer (Pied de page)
Classes : `bj-footer`, `bj-footer__top`, `bj-footer__top-row`, `bj-footer__col-title`, `bj-footer__list`, `bj-footer__link`, `bj-footer__partners`, `bj-footer__bottom`, `bj-footer__bottom-list`, `bj-footer__bottom-link`, `bj-footer__copy`
ARIA : `role="contentinfo"` sur footer
```html
```
### Bouton
Classes : `bj-btn`, `bj-btn--secondary`, `bj-btn--tertiary`, `bj-btn--accent`, `bj-btn--contrast`, `bj-btn--sm`, `bj-btn--lg`, `bj-btn--icon`, `bj-btn--full`, `bj-btn--disabled`, `bj-btn-group`, `bj-btn-group--vertical`, `bj-btn-group--inline-sm`
```html
Primaire
Secondaire
Tertiaire
Petit
Grand
Action 1
Action 2
```
### Lien
Classes : `bj-link`, `bj-link--sm`, `bj-link--lg`, `bj-link--icon-left`, `bj-link--icon-right`, `bj-link--reset`
```html
Lien simple
En savoir plus
```
### Badge
Classes : `bj-badge`, `bj-badge--info`, `bj-badge--success`, `bj-badge--warning`, `bj-badge--error`, `bj-badge--new`, `bj-badge--sm`, `bj-badge--no-icon`
```html
Par défaut
Validé
Erreur
Nouveau
```
### Tag
Classes : `bj-tag`, `bj-tag--action`, `bj-tag--info`, `bj-tag--success`, `bj-tag--warning`, `bj-tag--error`, `bj-tag--sm`, `bj-tag--dismiss`, `bj-tag__close`, `bj-tags`
```html
Étiquette
Supprimable ×
Info
Succès
```
### Avatar
Classes : `bj-avatar`, `bj-avatar--sm`, `bj-avatar--lg`, `bj-avatar--xl`, `bj-avatar--square`, `bj-avatar__img`, `bj-avatar__initials`, `bj-avatar__icon`, `bj-avatar__status`, `bj-avatar__status--online`, `bj-avatar__status--away`, `bj-avatar__status--busy`, `bj-avatar__status--offline`, `bj-avatar-group`
ARIA : `alt` sur img, `aria-hidden="true"` si avatar décoratif
```html
AB
```
### Alerte
Classes : `bj-alert`, `bj-alert--info`, `bj-alert--success`, `bj-alert--warning`, `bj-alert--error`, `bj-alert--sm`, `bj-alert__body`, `bj-alert__title`, `bj-alert__text`, `bj-alert__close`
ARIA : `role="alert"` pour alertes dynamiques, bouton fermeture avec `aria-label`
```html
Information
Votre demande a bien été prise en compte.
Erreur
La soumission a échoué.
×
```
### Carte
Classes : `bj-card`, `bj-card__img`, `bj-card__body`, `bj-card__detail`, `bj-card__title`, `bj-card__desc`, `bj-card__footer`, `bj-card--horizontal`, `bj-card--flat`, `bj-card--highlight`, `bj-card--link`, `bj-cards`
```html
Catégorie
Titre de la carte
Description du contenu.
```
### Tuile
Classes : `bj-tile`, `bj-tile__icon`, `bj-tile__img`, `bj-tile__body`, `bj-tile__title`, `bj-tile__desc`, `bj-tile--horizontal`, `bj-tiles`
```html
Service public
Accédez à vos démarches
```
### Accordéon
Classes : `bj-accordion`, `bj-accordion__btn`, `bj-accordion__body`, `bj-accordion--expanded`, `data-bj-accordion-group`
ARIA : `aria-expanded`, `aria-controls` sur bouton, `id` sur panel
JS : `data-bj-accordion-btn`, `data-bj-expanded` pour état ouvert
```html
```
### Onglet (Tabs)
Classes : `bj-tabs__list`, `bj-tabs__tab`, `bj-tabs__panel`
ARIA : `role="tablist"`, `role="tab"`, `role="tabpanel"`, `aria-selected`
JS : `data-bj-tabs` sur conteneur, `data-bj-tab`, `data-bj-tab-panel`, `data-bj-expanded`
```html
Onglet 1
Onglet 2
Contenu du premier onglet.
Contenu du deuxième onglet.
```
### Modale
Classes : `bj-modal`, `bj-modal__overlay`, `bj-modal__dialog`, `bj-modal__header`, `bj-modal__title`, `bj-modal__close`, `bj-modal__body`, `bj-modal__footer`, `bj-modal--sm`, `bj-modal--lg`, `bj-modal--full`
ARIA : `role="dialog"`, `aria-modal="true"`, `aria-labelledby`
JS : `data-bj-modal-open="id"`, `data-bj-modal-close`, focus trap automatique
```html
Ouvrir
```
### Champ de saisie (Input)
Classes : `bj-input-group`, `bj-label`, `bj-hint`, `bj-input`, `bj-input--sm`, `bj-input-group--valid`, `bj-input-group--error`, `bj-message`, `bj-message--valid`, `bj-message--error`, `bj-message--info`, `bj-input-wrap`, `bj-input-wrap__icon`
```html
```
### Liste déroulante (Select)
Classes : `bj-select-group`, `bj-select`, `bj-select--error`
```html
Département
Choisir
Littoral
Atlantique
```
### Case à cocher (Checkbox)
Classes : `bj-checkbox-group`, `bj-checkbox-group__legend`, `bj-checkbox`, `bj-checkbox__label`, `bj-checkbox__hint`
```html
Options
Option 1
Option 2
```
### Bouton radio
Classes : `bj-radio-group`, `bj-radio-group--inline`, `bj-radio-group__legend`, `bj-radio`, `bj-radio__label`, `bj-radio__hint`
```html
Civilité
Monsieur
Madame
```
### Interrupteur (Toggle)
Classes : `bj-toggle`, `bj-toggle__input`, `bj-toggle__label`, `bj-toggle__hint`
```html
Activer les notifications
```
### Breadcrumb (Fil d'Ariane)
Classes : `bj-breadcrumb`, `bj-breadcrumb__list`, `bj-breadcrumb__item`, `bj-breadcrumb__link`
ARIA : `aria-label="Fil d'Ariane"` sur nav, `aria-current="page"` sur dernier item
```html
Accueil
Services
Mon service
```
### Navigation
Classes : `bj-nav`, `bj-nav__list`, `bj-nav__item`, `bj-nav__link`, `bj-nav__btn`
```html
```
### Bandeau (Notice)
Classes : `bj-notice`, `bj-notice__icon`, `bj-notice__body`, `bj-notice__title`, `bj-notice__close`, `bj-notice--info`, `bj-notice--warning`, `bj-notice--alert`
```html
```
### Mise en avant (Callout)
Classes : `bj-callout`, `bj-callout__icon`, `bj-callout__title`, `bj-callout__text`, `bj-callout__btn`, `bj-callout--green`, `bj-callout--yellow`, `bj-callout--red`
```html
Titre de la mise en avant
Texte descriptif avec informations complémentaires.
Action
```
### Mise en exergue (Highlight)
Classes : `bj-highlight`, `bj-highlight--sm`, `bj-highlight--lg`
```html
Texte important mis en exergue pour attirer l'attention du lecteur.
```
### Citation (Quote)
Classes : `bj-quote`, `bj-quote__text`, `bj-quote__author`, `bj-quote__source`, `bj-quote--accent`, `bj-quote__image`
```html
Le texte de la citation.
AuteurSource
```
### Tableau (Table)
Classes : `bj-table-wrapper`, `bj-table`, `bj-table--bordered`, `bj-table--striped`, `bj-table--layout-fixed`, `bj-table--no-caption`
```html
Titre du tableau
Nom Valeur
Donnée 1 Valeur 1
```
### Skiplink (Lien d'évitement)
Classes : `bj-skiplinks`, `bj-skiplinks__list`, `bj-skiplinks__link`
```html
```
### Pagination
Classes : `bj-pagination`, `bj-pagination__link`, `bj-pagination__link--active`, `bj-pagination__link--disabled`, `bj-pagination__ellipsis`, `bj-pagination__nav`, `bj-pagination__nav--disabled`, `bj-pagination__label`
```html
```
### Infobulle (Tooltip)
Classes : `bj-tooltip`, `bj-tooltip__content`
```html
Survolez-moi
Texte de l'infobulle
```
### Indicateur d'étapes (Stepper)
Classes : `bj-stepper`, `bj-stepper__header`, `bj-stepper__title`, `bj-stepper__detail`, `bj-stepper__steps`, `bj-stepper__step`, `bj-stepper--vertical`
```html
Identité
Adresse
Pièces jointes
Récapitulatif
```
### Notification toast
Classes : `bj-toast-container`, `bj-toast`, `bj-toast--info`, `bj-toast--success`, `bj-toast--warning`, `bj-toast--error`, `bj-toast__progress`, `bj-toast-container--top-left`, `bj-toast-container--bottom-right`
JS : `toast('Message', { type: 'success' })`
```html
```
### Menu déroulant (Dropdown)
Classes : `bj-dropdown`, `bj-dropdown__trigger`, `bj-dropdown__menu`, `bj-dropdown__item`, `bj-dropdown__divider`, `bj-dropdown__header`, `bj-dropdown--right`, `bj-dropdown--up`, `bj-dropdown--sm`
```html
Actions
```
### Bandeau défilant (Marquee)
Classes : `bj-marquee`, `bj-marquee__track`, `bj-marquee__item`, `bj-marquee__pause`, `bj-marquee--reverse`, `bj-marquee--slow`, `bj-marquee--fast`, `bj-marquee--bordered`
ARIA : `aria-live="polite"` ou `aria-live="off"` selon le contexte, `aria-label` sur le bouton pause
```html
Annonce importante
Deuxième annonce
⏸
```
### Galerie d'images
Classes : `bj-gallery`, `bj-gallery__item`, `bj-gallery__img`, `bj-gallery__caption`, `bj-gallery--cols-2`, `bj-gallery--cols-4`
```html
Légende
```
### Skeleton (Placeholder de chargement)
Classes : `bj-skeleton`, `bj-skeleton--text`, `bj-skeleton--heading`, `bj-skeleton--circle`, `bj-skeleton--rect`, `bj-skeleton--sm`, `bj-skeleton--lg`, `bj-skeleton-group`
ARIA : `aria-busy="true"` sur le conteneur, `aria-hidden="true"` sur les skeletons
```html
```
### Bannière (Banner)
Classes : `bj-banner`, `bj-banner__img`, `bj-banner__overlay`, `bj-banner__body`, `bj-banner__title`, `bj-banner__text`, `bj-banner__actions`, `bj-banner--sm`, `bj-banner--lg`, `bj-banner--center`, `bj-banner--right`, `bj-banner--light`, `bj-banner--dark`, `bj-banner--plain`, `bj-banner--green`, `bj-banner--yellow`, `bj-banner--red`
```html
Bienvenue sur le portail
Accédez à vos démarches en ligne.
```
### Arborescence (Treeview)
Classes : `bj-tree`, `bj-tree__item`, `bj-tree__item-content`, `bj-tree__branch`, `bj-tree__toggle`, `bj-tree__toggle-spacer`, `bj-tree__label`, `bj-tree__icon`, `bj-tree__checkbox`, `bj-tree--checkbox`, `bj-tree--compact`
ARIA : `role="tree"`, `role="treeitem"`, `role="group"`, `aria-expanded`
JS : `data-bj-tree-toggle`
```html
```
### Bulle de chat (Chat Bubble)
Classes : `bj-chat-bubble`, `bj-chat-bubble__avatar`, `bj-chat-bubble__content`, `bj-chat-bubble__text`, `bj-chat-bubble__time`, `bj-chat-bubble__status`, `bj-chat-bubble__sender`, `bj-chat-bubble__meta`, `bj-chat-bubble--sent`, `bj-chat-bubble--received`, `bj-chat-bubble--system`, `bj-chat-bubble--error`
ARIA : `role="listitem"`, `aria-label`
```html
```
### Tiroir (Drawer)
Classes : `bj-drawer`, `bj-drawer__overlay`, `bj-drawer__panel`, `bj-drawer__header`, `bj-drawer__title`, `bj-drawer__close`, `bj-drawer__body`, `bj-drawer__footer`, `bj-drawer--right`, `bj-drawer--sm`, `bj-drawer--lg`, `bj-drawer--full`
ARIA : `role="dialog"`, `aria-modal="true"`, `aria-labelledby`, `aria-label="Fermer"`
JS : `data-bj-drawer-open`, `data-bj-drawer-close`
```html
Ouvrir le tiroir
```
### Consentement (RGPD)
Classes : `bj-consent-banner`, `bj-consent-banner__body`, `bj-consent-banner__header`, `bj-consent-banner__title`, `bj-consent-banner__text`, `bj-consent-banner__actions`, `bj-consent-manager`, `bj-consent-manager__dialog`, `bj-consent-manager__header`, `bj-consent-manager__body`, `bj-consent-manager__footer`, `bj-consent-service`, `bj-consent-service__name`, `bj-consent-service__desc`, `bj-consent-service__toggle`
```html
Ce site utilise des cookies pour améliorer votre expérience.
Tout accepter
Tout refuser
Personnaliser
```
### Combobox (Autocomplétion)
Classes : `bj-combobox`, `bj-combobox__input-wrap`, `bj-combobox__input`, `bj-combobox__icon`, `bj-combobox__listbox`, `bj-combobox__option`, `bj-combobox__option--active`, `bj-combobox__no-results`, `bj-combobox--open`, `bj-combobox--error`
ARIA : `role="combobox"`, `aria-expanded`, `aria-autocomplete="list"`, `aria-haspopup="listbox"`, `aria-controls`, `aria-activedescendant`, `role="listbox"`, `role="option"`, `aria-selected`, `aria-disabled`
```html
```
Variante select custom avec recherche :
```html
```
### Éditeur riche (Rich Editor)
Classes : `bj-rich-editor`, `bj-rich-editor--disabled`, `bj-rich-editor__toolbar`, `bj-rich-editor__toolbar-group`, `bj-rich-editor__toolbar-separator`, `bj-rich-editor__toolbar-btn`, `bj-rich-editor__toolbar-btn--active`, `bj-rich-editor__toolbar-select`, `bj-rich-editor__color-picker`, `bj-rich-editor__content`
ARIA : `role="toolbar"` + `aria-label` sur la barre d'outils, `role="textbox"` + `aria-multiline="true"` sur la zone de contenu, `aria-label` sur chaque bouton
Outils disponibles : heading, bold, italic, underline, strikethrough, unorderedList, orderedList, indent, outdent, alignLeft, alignCenter, alignRight, alignJustify, link, unlink, image, video, table, blockquote, codeBlock, removeFormat, textColor, bgColor, horizontalRule, undo, redo
```html
```
### Sélecteur de date (Datepicker)
Classes : `bj-datepicker`, `bj-datepicker__input`, `bj-datepicker__trigger`, `bj-datepicker__calendar`, `bj-datepicker__day--today`, `bj-datepicker__day--selected`, `bj-datepicker--sm`
```html
Date de naissance
```
### Recherche
Classes : `bj-search`, `bj-search__input`, `bj-search__btn`, `bj-search--lg`
```html
```
### Téléversement (Upload)
Classes : `bj-upload-group`, `bj-upload-group--error`, `bj-upload`, `bj-upload--drag-over`
```html
Pièce jointe
```
### Logo
Classes : `bj-logo`, `bj-logo--lg`, `bj-logo--xl`, `bj-logo__link`, `bj-logo__motto`, `bj-logo__tagline`
```html
République du Bénin
Fraternité, Justice, Travail
```
### Sidemenu (Menu latéral)
Classes : `bj-sidemenu`, `bj-sidemenu__title`, `bj-sidemenu__list`, `bj-sidemenu__item`, `bj-sidemenu__sublist`, `bj-sidemenu__btn`
```html
```
### Sommaire
Classes : `bj-summary`, `bj-summary__title`, `bj-summary__list`, `bj-summary__link`
```html
Sommaire
```
### Contenu éditorial
Classes : `bj-content`
```html
Titre de l'article
Paragraphe avec typographie optimisée pour la lecture.
Sous-titre
```
### Dashboard Sidebar
Classes : `bj-dashboard-sidebar`, `bj-dashboard-sidebar--compact`, `bj-dashboard-sidebar__brand`, `bj-dashboard-sidebar__brand-img`, `bj-dashboard-sidebar__brand-text`, `bj-dashboard-sidebar__nav`, `bj-dashboard-sidebar__section`, `bj-dashboard-sidebar__section-title`, `bj-dashboard-sidebar__list`, `bj-dashboard-sidebar__item`, `bj-dashboard-sidebar__link`, `bj-dashboard-sidebar__link--active`, `bj-dashboard-sidebar__link-icon`, `bj-dashboard-sidebar__link-label`, `bj-dashboard-sidebar__btn`, `bj-dashboard-sidebar__sublist`, `bj-dashboard-sidebar__footer`
ARIA : `aria-label="Navigation du tableau de bord"`, `aria-current="page"`, `aria-expanded`, `aria-controls`
```html
```
### Chart (Conteneur générique)
Classes : `bj-chart`, `bj-chart__header`, `bj-chart__title`, `bj-chart__subtitle`, `bj-chart__body`, `bj-chart__legend`, `bj-chart__legend-item`, `bj-chart__legend-dot`
```html
```
### Chart Bar (Graphique en barres)
Classes : `bj-chart-bar`, `bj-chart-bar--horizontal`, `bj-chart-bar__col`, `bj-chart-bar__bar`, `bj-chart-bar__label`, `bj-chart-bar__value`, `bj-chart-bar__row`, `bj-chart-bar__track`, `bj-chart-bar__fill`
ARIA : `role="img"`, `aria-label`
```html
```
### Chart Line (Graphique en lignes)
Classes : `bj-chart-line`, `bj-chart-line__path`, `bj-chart-line__area`, `bj-chart-line__dot`, `bj-chart-line__grid`, `bj-chart-line__axis`
ARIA : `role="img"`, `aria-label`
```html
```
### Chart Pie (Graphique camembert)
Classes : `bj-chart-pie`, `bj-chart-pie--donut`, `bj-chart-pie__slice`, `bj-chart-pie__label`, `bj-chart-pie__center`, `bj-chart-pie__center-text`
ARIA : `role="img"`, `aria-label`
```html
```
---
## Règles d'accessibilité DSBJ
1. Toujours utiliser `aria-hidden="true"` sur les icônes décoratives (``)
2. Les composants interactifs nécessitent `aria-expanded`, `aria-controls`, `aria-label` selon le contexte
3. Les modales utilisent `role="dialog"`, `aria-modal="true"`, `aria-labelledby`, et un focus trap
4. Les onglets utilisent `role="tablist"`, `role="tab"`, `role="tabpanel"`, `aria-selected`
5. Les alertes dynamiques utilisent `role="alert"`
6. Le breadcrumb utilise `aria-current="page"` sur l'élément actif
7. Un seul `` par page, hiérarchie de titres stricte (h1 > h2 > h3...)
8. Skip links en début de page vers `#main`
9. Tous les champs de formulaire ont un `` associé
10. Les erreurs de formulaire utilisent `aria-describedby` + `aria-invalid="true"`