Aller au contenu principal
Tous les articles
·3 min de lecture

Tailwind CSS v4 : construire un design system SaaS en 1 journée

Tokens CSS, dark mode, composants réutilisables — comment structurer un design system professionnel avec Tailwind v4 et shadcn/ui.

tailwindcssdesign-systemui

Pourquoi un design system dès le jour 1 ?

Un SaaS sans design system finit toujours pareil : des couleurs hardcodées partout, un dark mode cassé, et des composants qu'on copie-colle au lieu de réutiliser.

Avec Tailwind CSS v4 et shadcn/ui, vous pouvez mettre en place un système solide en moins d'une journée. Voici comment on l'a fait pour HeartCo.

Étape 1 — Les tokens CSS

Tailwind v4 introduit les tokens CSS natifs. Plus besoin de tailwind.config.js pour les couleurs — tout passe par des variables CSS :

/* globals.css */
@theme {
  --color-brand: #4f46e5;
  --color-deep-navy: #0d1b2a;
  --color-ai-blue: #3b82f6;
  --color-ai-cyan: #06b6d4;
}

L'avantage ? Le dark mode devient trivial

:root {
  --color-background: oklch(0.984 0.003 247.858);
  --color-foreground: oklch(0.141 0.005 285.823);
}
 
.dark {
  --color-background: oklch(0.141 0.005 285.823);
  --color-foreground: oklch(0.984 0.003 247.858);
}

Vos composants utilisent bg-background et text-foreground — le thème switch automatiquement. Zéro dark: prefix à gérer manuellement.

Étape 2 — La librairie de composants

shadcn/ui n'est pas une dépendance npm — c'est un générateur de code. Vous copiez les composants dans votre projet et les personnalisez :

npx shadcn@latest add button card dialog

Le secret : ne jamais modifier les primitives directement. Créez des wrappers métier :

// src/components/ui/heart-button.tsx
import { Button, type ButtonProps } from "~/components/ui/button";
import { cn } from "~/lib/utils";
 
export function HeartButton({
  variant = "default",
  className,
  ...props
}: ButtonProps) {
  return (
    <Button
      className={cn(
        "transition-all duration-200",
        "hover:scale-[1.02] active:scale-[0.98]",
        variant === "primary" &&
          "bg-brand text-white shadow-[0_0_20px_rgba(99,102,241,0.3)]",
        className,
      )}
      {...props}
    />
  );
}

Étape 3 — La fonction cn() — votre meilleur ami

// src/lib/utils.ts
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
 
export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

cn() résout le problème classique de Tailwind : quand deux classes conflictuelles se rencontrent (p-4 + p-6), twMerge garde la dernière. Sans ça, les overrides de styles sont imprévisibles.

Étape 4 — Les règles du design system

Quelques règles qu'on applique strictement dans HeartCo :

  1. Jamais de couleurs hardcodées — Toujours des tokens (text-foreground, pas text-gray-900)
  2. Jamais de dark: prefix — Les tokens gèrent le thème
  3. Hover states obligatoires — Chaque élément interactif a un feedback visuel
  4. Cards avec ombres, pas de bordures — Plus moderne, plus élégant
  5. Titres en display font — Séparer visuellement heading et body

Résultat

Avec cette structure, ajouter un nouveau composant prend 5 minutes au lieu de 30. Le dark mode fonctionne partout. Et votre SaaS a un look professionnel dès le premier jour.

Dans le prochain article, on parlera sécurité multi-tenant avec Prisma — le vrai sujet critique quand on construit un SaaS B2B.