Ressources techniques
D

design.md

active

Conventions UI communes à tous nos projets : stack, primitives, patterns custom, accessibilité minimale, copy.

standard · mise à jour 10 juin 2026

designuitailwindaccessibilityconventions

Design : cross-project conventions

Applies to every project. Project-specific rules (color tokens, typography, density, animations, i18n) belong in the design-system.md at the project root.


Universal UI stack

  • Tailwind CSS (v3 or v4 depending on the project, never mixed within one project)
  • Radix UI + shadcn/ui : primitive library, never replaced by Ant Design, MUI, Chakra
  • CVA (class-variance-authority) : component variants
  • tailwind-merge : conflict-free class merging
  • cn() utility : clsx + tailwind-merge, exported from src/lib/utils.ts
  • Lucide React : icons (not heroicons, not react-icons)

Component organization

src/components/
  ui/          ← shadcn primitives (atoms)
  design/      ← reusable domain components (molecules)
  layout/      ← Sidebar, Topbar, Navbar, Footer
  [domain]/    ← feature-specific components
  • PascalCase for files: FormField.tsx, StatusBadge.tsx
  • Named export + displayName for forwardRef components
  • Props type: ${ComponentName}Props (e.g. ButtonProps)

shadcn primitives (always present)

Atoms: Button, Input, Textarea, Label, Checkbox, Switch, Select, Badge, Avatar, Skeleton

Molecules: Card, Dialog, DropdownMenu, Tabs, Tooltip, Popover, RadioGroup

Never rebuild these from scratch. Extend them via CVA or wrapping when needed.


Recurring custom patterns

Combobox

  • Built on cmdk (Command + CommandInput + CommandList), not Radix Select
  • Live search on keystroke, no submit button
  • Clear button (× icon, size-3) on the right, stopPropagation
  • Dropdown chevron on the right, text-gray-400 size-3.5
  • Search placeholder: "Rechercher…"
  • Empty state: "Aucun X trouvé"
  • Max 50 results shown (filter/paginate beyond that)
  • Keyboard: arrows to navigate, Enter to select, Escape to close

FormField

<div className="flex flex-col gap-1.5">
  <Label htmlFor={id}>{label}</Label>
  <Input id={id} aria-invalid={!!error} aria-describedby={error ? errorId : undefined} />
  {error && <p id={errorId} className="text-xs text-danger" role="alert">{error}</p>}
  {helpText && !error && <p className="text-xs text-gray-500">{helpText}</p>}
</div>

DataTable

  • Skeleton rows (h-4 w-full) while loading
  • Empty state: "Aucun résultat", centered
  • Columns via render: (row) => ReactNode callback
  • Semantic structure: <Table>, <TableHeader>, <TableBody>, <TableRow>, <TableCell>

StatusBadge

  • outline variant with semantic colors
  • Colors: success (green), warning (amber), danger (red), info (blue), neutral (gray)
  • Labels in French: "Actif", "En attente", "Erreur", "Inactif", etc.

Accessibility (non-negotiable minimum)

  • Inputs: aria-invalid={!!error}, aria-describedby pointing to the error message ID
  • Errors: role="alert" on the message, automatic announcement
  • Visible focus: focus-visible:ring-2 focus-visible:ring-offset-1, never remove outline
  • Disabled: disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
  • Decorative icons: no aria-label (Lucide renders them decorative by default)
  • Meaningful icons (no adjacent text): aria-label required
  • Modals: trap focus (Radix Dialog handles it), Escape to close
  • Labels: always htmlFor bound to the input id, never a visual label without a link

UI copy (French by default)

  • Empty states: "Aucun X trouvé" / "Aucun résultat"
  • Actions: "Ajouter", "Supprimer", "Enregistrer", "Annuler", "Modifier"
  • Destructive confirmation: "Supprimer définitivement" (not just "Supprimer")
  • Search placeholder: "Rechercher…"
  • Loading: "Chargement…" (not "Loading...")
  • No in visible text (see global CLAUDE.md rule)

What does NOT belong here (→ project design-system.md)

  • Color tokens (primary palette, semantic, dark mode)
  • Typography (font choice, base size, weights)
  • Density (compact back-office 14px vs relaxed marketing 16px)
  • Custom animations and micro-interactions
  • i18n approach and routing conventions
  • Breakpoints and specific layout max-width