Les deux design systems de Stripe, et pourquoi ils divergent

Cherchez le design system de Stripe et vous trouverez des personnes qui ne cherchent pas la bonne chose. Le système interne de Stripe n'est pas publié. Ce qui est publié, ce sont deux systèmes destinés aux clients qui font des paris diamétralement opposés sur qui est autorisé à contrôler les pixels — et la raison de cette divergence a plus de valeur que n'importe quel fichier de tokens.

Mis à jour 2026-07-27

Analyse indépendante de la documentation publique pour développeurs de Stripe, écrite pour les personnes concevant leurs propres systèmes. Identity Forge n'est pas affilié à Stripe et n'est pas approuvé par Stripe. Stripe et son logo sont des marques déposées de leur propriétaire. Les détails présentés ici reflètent la documentation au moment de la rédaction ; veuillez vérifier sur docs.stripe.com avant de vous baser sur une valeur spécifique.

Ce que les gens recherchent n'existe pas publiquement

Les propres surfaces produits de Stripe — le Dashboard, le site marketing, la documentation — fonctionnent sur un système interne qui a porté divers noms au fil des ans et n'a jamais été publié sous forme de package public. Il n'y a pas de npm install, pas de Storybook, pas d'export de tokens. Si c'est ce que vous cherchiez, ce n'est pas disponible, et les reconstructions tierces ne sont que des déductions basées sur des captures d'écran.

Ce que Stripe publie, et documente minutieusement, ce sont deux systèmes destinés aux développeurs qui s'intègrent à Stripe. Ils sont généralement abordés séparément car ils se trouvent dans des sections différentes de la documentation. Lus ensemble, ils constituent une véritable masterclass sur les limites d'un design system.

Stripe Apps UI toolkitElements Appearance API
Lieu de rendu de l'UIDans le Dashboard StripeDans votre produit
Marque dominanteCelle de StripeLa vôtre
CSS arbitraireImpossible — la prop css n'accepte que des tokensSupporté, via la map rules
EspacementSept paliers nommés et fixesUn spacingUnit que vous définissez ; tout en dérive
Stylisation des composantsPrédéfinie ; certains composants refusent toute surchargePersonnalisable jusqu'aux sélecteurs et états individuels
Ce qu'il optimiseLa cohérence entre des milliers d'applications tiercesL'intégration fluide dans un checkout que vous n'avez pas conçu
Deux systèmes Stripe publics, deux postures opposées.

La frontière entre les deux n'est pas technique. C'est une limite de confiance. Lorsque votre interface utilisateur se trouve sur la surface de Stripe, Stripe ne peut pas permettre qu'une application tierce mal stylisée donne l'impression que le Dashboard est cassé, donc elle supprime cette possibilité. Lorsque l'interface de Stripe se trouve sur votre surface, un formulaire de paiement qui ignorerait votre design ressemblerait à un problème de sécurité, alors Stripe vous remet les commandes. Même entreprise, mêmes valeurs de design, réglages par défaut opposés — car la question n'est pas « à quoi cela doit-il ressembler », mais « qui est responsable de l'apparence ».

Stripe Apps : un design system imposé par la signature de type

Le kit UI de Stripe Apps vous fournit un ensemble de composants — vues, mise en page, navigation, contenu, formulaires, graphiques — ainsi qu'une primitive Box avec une prop css. La prop css ressemble à une porte de sortie pour le stylisage, mais elle n'en est pas une. Elle accepte des tokens nommés, et rien d'autre.

<Box css={{
  stack: 'y',
  gap: 'medium',
  padding: 'large',
  backgroundColor: 'surface',
  borderRadius: 'medium',
}} />

// gap: 'medium'  ✅  a token
// gap: '17px'    ❌  not in the vocabulary

Le vocabulaire d'espacement se compose de sept étapes et d'un zéro, documentés avec des valeurs de pixels fixes : xxsmall 2px, xsmall 4px, small 8px, medium 16px, large 24px, xlarge 32px, xxlarge 48px. Le dimensionnement est fractionnaire — demis, tiers, quarts, cinquièmes, sixièmes, douzièmes, plus fill — avec des options min, max et fit basées sur le contenu.

Notez les ratios de cette échelle d'espacement. Elle n'est pas linéaire (2, 4, 8, 16, 24, 32, 48) : elle double pour les petites valeurs là où des différences de 2px sont visibles, puis progresse par paliers de 8 pour les grandes valeurs là où elles ne le sont pas. Une échelle qui doublerait jusqu'à 128 gaspillerait des étapes que personne n'utilise ; une échelle qui progresserait par 4 tout au long donnerait treize valeurs qui se ressembleraient toutes.

La partie intéressante est ce qui se passe au-dessus de Box. Les composants autres que Box et Inline portent des styles prédéfinis, et la documentation précise explicitement que certains d'entre eux ne peuvent pas être modifiés du tout — un composant qui change d'apparence selon les callbacks qu'il implémente ne vous laissera pas contredire cela, car l'apparence véhicule un sens. D'autres exposent un petit enum : Button possède primary, le défaut et destructive, et c'est toute la liste. Quelques-uns exposent une seule propriété, comme Icon qui accepte fill.

Il existe également un ensemble documenté de contraintes de hiérarchie de composants — des règles sur quels composants peuvent en contenir d'autres. C'est l'équivalent pour la mise en page de la même idée : non pas un conseil sur une bonne structure, mais une restriction qui fait qu'une mauvaise structure échoue plutôt que d'être déployée.

La leçon : l'imposition l'emporte sur la documentation

Presque chaque design system est un projet de documentation. Il dit d'utiliser les tokens, puis livre une prop className qui accepte n'importe quoi, et six mois plus tard, la moitié de la base de code contient des valeurs hexadécimales arbitraires parce que quelqu'un était pressé un vendredi.

Stripe Apps supprime cette option. Il n'y a aucun chemin menant de « être pressé » à #3c82f6, car la prop ne l'acceptera pas. C'est une garantie bien plus forte qu'une règle de linting et infiniment plus forte qu'un paragraphe dans un wiki. Si vous maintenez un système qui doit survivre à des contributeurs qui n'ont pas lu la doc — c'est-à-dire tous — c'est la stratégie à adopter.

C'est aussi la stratégie au coût le plus élevé, et il faut être honnête là-dessus. Un vocabulaire fermé signifie que chaque nouveau besoin réel devient une demande adressée aux propriétaires du système. C'est tolérable quand les propriétaires sont une équipe plateforme financée servant une marketplace d'applications. C'est misérable quand il s'agit d'une seule personne maintenant un système pour quatre squads produit qui ont toutes des deadlines.

Elements : l'échelle à trois niveaux

L'API Appearance résout le problème inverse. Un formulaire de paiement doit sembler natif sur un site que personne chez Stripe n'a vu, tout en conservant une mise en page contrôlée par Stripe pour des raisons de conversion et de conformité. La réponse de Stripe est une échelle à trois barreaux, et la documentation vous demande de les gravir dans l'ordre.

  1. 1

    Choisir un thème

    Trois points de départ préconfigurés — stripe, night, flat. Une ligne de code, et la plupart des intégrations qui ont seulement besoin de ne pas jurer avec le reste sont terminées ici.

    const appearance = { theme: 'night' }
  2. 2

    Définir des variables

    Un petit ensemble de valeurs qui se propagent partout. C'est la couche de tokens, et c'est là que se produit la majorité de la personnalisation réelle.

    const appearance = {
      theme: 'stripe',
      variables: {
        colorPrimary: '#0570de',
        colorBackground: '#ffffff',
        colorText: '#30313d',
        colorDanger: '#df1b41',
        fontFamily: 'Ideal Sans, system-ui, sans-serif',
        spacingUnit: '2px',
        borderRadius: '4px',
      },
    }
  3. 3

    Ajouter des règles, seulement si c'est encore nécessaire

    Une table de correspondance entre des sélecteurs de type CSS et des propriétés CSS, ciblant des composants et des états individuels. C'est la porte de sortie, et elle est délibérément placée en dernier.

    const appearance = {
      rules: {
        '.Tab': { border: '1px solid #E0E6EB' },
        '.Tab:hover': { color: 'var(--colorText)' },
        '.Tab--selected': { borderColor: '#E0E6EB' },
      },
    }

L'ordre fait partie du design. Chaque barreau est plus puissant et plus coûteux à maintenir que celui du dessous, et la documentation vous pousse à descendre l'échelle plutôt qu'à la monter. Une équipe qui commence par les rules écrit quarante sélecteurs et doit les maintenir pour toujours ; une équipe qui commence par le theme écrit une ligne et ne descend que lorsqu'elle y est réellement contrainte.

spacingUnit est l'idée de design de token qui vaut la peine d'être volée

Parmi les variables, deux méritent l'attention car elles sont des bases dérivées plutôt que des valeurs. spacingUnit est décrite comme l'unité de base dont découle tout l'espacement — augmentez-la et tout le composant devient plus aéré. fontSizeBase définit la taille racine, et les autres variables de taille de police s'y adaptent en rem.

Comparez cela avec l'approche habituelle, où un design system publie --space-1 jusqu'à --space-12 comme douze valeurs codées en dur et indépendantes. Les deux vous donnent une échelle. Une seule vous donne un curseur. Si un client a besoin d'un formulaire plus dense, la version dérivée nécessite un seul chiffre ; la version énumérée nécessite douze modifications et un arbitrage pour chacune.

/* Enumerated: twelve values, twelve things to change */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
/* ... */

/* Derived: one dial */
--space-unit: 4px;
--space-1: calc(var(--space-unit) * 1);
--space-2: calc(var(--space-unit) * 2);
--space-3: calc(var(--space-unit) * 3);

Cela vaut la peine d'être appliqué au-delà de l'espacement. Toute échelle où les étapes sont véritablement proportionnelles — espacement, typographie, rayons de bordure — est mieux exprimée par une base plus un ratio que par une liste. Les échelles où les étapes ne sont pas proportionnelles, comme une rampe de couleurs neutres, ne le sont pas : celles-ci nécessitent que chaque étape soit choisie à l'œil.

Les exceptions documentées sont la partie honnête

La documentation de l'API Appearance stipule que colorPrimary, colorBackground, colorText, colorSuccess, colorDanger et colorWarning ne supportent pas la syntaxe rgba() ou var(--myVariable), alors que d'autres variables le font. Elle note également que l'API ne s'applique pas aux Elements de méthode de paiement individuels comme CardElement, qui utilisent un objet Style distinct.

Ce sont des incohérences sans prestige, et les publier est la bonne décision. Une API de personnalisation qui échoue silencieusement sur un sous-ensemble d'entrées coûte à l'intégrateur une après-midi de débogage confus ; une API qui le précise dans le tableau lui coûte trente secondes. Si votre propre système a une règle qui ne fonctionne que dans certains cas, c'est dans la documentation que cela doit figurer, pas dans le changelog.

Appliquer les deux modèles à un système destiné aux agents

Ces deux systèmes ont été conçus pour des développeurs humains lisant de la documentation. La question intéressante en 2026 est ce qui change quand le développeur est un agent de code, et la réponse est que la posture de Stripe Apps se renforce tandis que celle d'Elements s'affaiblit.

Un agent n'a aucun intérêt à brûler les étapes un vendredi, mais il n'a pas non plus de mémoire de vos conventions entre deux sessions. Donnez-lui un vocabulaire fermé et il utilisera ce vocabulaire, fidèlement, pour toujours. Donnez-lui une prop className et un paragraphe disant « préférez les tokens » et il utilisera les tokens environ aussi souvent que les données d'entraînement le font — c'est-à-dire, parfois.

Nous avons analysé 299 fichiers DESIGN.md publiés pour être lus par des agents IA. 86 % spécifiaient les couleurs comme des valeurs hexadécimales brutes sans rôle sémantique associé, et 76 % ne contenaient aucune interdiction. Ces deux chiffres décrivent un fichier qui indique au modèle quelles couleurs existent, mais rien sur leur signification ou sur ce qui est interdit — l'exact opposé des deux systèmes de Stripe, qui portent presque entièrement sur le sens et la contrainte.

Ce que le modèle en fait
Primary: #0570deL'utilise partout où le bleu semble raisonnable — titres, liens, bordures, dégradé
--color-primary: #0570de — actions primaires et état actif uniquement. Jamais pour le texte, les bordures ou les arrière-plans.L'utilise pour les actions primaires et l'état actif. C'est l'interdiction qui fait la différence
Spacing: 4, 8, 12, 16, 24, 32Utilise principalement ces valeurs, avec occasionnellement du 14px ou du 20px lorsque la mise en page est très serrée
Spacing scale is xs/sm/md/lg/xl only. Any other value is a bug.Respecte l'échelle, car le fichier définit ce qui est considéré comme incorrect
La même consigne, écrite sous forme de liste de valeurs et écrite sous forme de vocabulaire.

C'est l'idée de Stripe Apps transposée en prose : vous ne pouvez pas infliger une erreur de type à un agent, mais vous pouvez lui indiquer ce qui en constituerait une. L'approche d'Elements se transpose également sous forme d'ordre de priorité — énoncez d'abord les valeurs par défaut au niveau du thème, puis les design tokens, puis les exceptions spécifiques, afin qu'un modèle lisant de haut en bas rencontre la règle générale avant le cas particulier.

Les kits de design d'Identity Forge sont construits précisément sur ce modèle : des rôles sémantiques plutôt que des hexadécimaux bruts, une liste explicite de ce qu'il faut faire et ne pas faire, et des motifs qui décrivent ce que fait le design plutôt que les valeurs qu'il contient. Parcourir les kits, ou commencez par découvrir ce qu'est un fichier DESIGN.md.

Ce qu'il faut en retenir

La plupart des équipes qui créent un design system choisissent une posture et l'appliquent partout. La documentation de Stripe démontre que la posture doit suivre la limite. Sur les surfaces dont vous êtes responsable, verrouillez le vocabulaire et rendez les violations impossibles. Sur les surfaces dont quelqu'un d'autre est responsable, publiez une échelle et laissez-les grimper seulement jusqu'au niveau dont ils ont besoin.

La plupart des produits possèdent les deux types de surfaces. L'outil d'administration interne et le widget intégrable ne constituent pas le même problème de design, et un système unique avec une seule logique de personnalisation desservira mal l'un d'entre eux.

Puis-je télécharger le design system de Stripe?

Pas celui utilisé en interne pour le Dashboard et le site marketing — il n'a jamais été publié sous forme de package ou de site de documentation. Le toolkit UI de Stripe Apps et l'API Appearance d'Elements sont tous deux publics et documentés, mais ce sont des systèmes pour s'intégrer à Stripe, pas pour construire votre propre produit.

Quelle est la différence entre Stripe Elements et le toolkit UI de Stripe Apps?

Elements est l'interface de paiement de Stripe que vous intégrez à votre site, stylisée pour correspondre à votre marque via l'API Appearance. Le toolkit UI de Stripe Apps est une bibliothèque de composants pour créer des applications qui s'affichent à l'intérieur du Dashboard Stripe, stylisée pour correspondre à la marque Stripe sans aucun moyen de la modifier. Des surfaces différentes, des propriétaires de l'apparence différents.

Puis-je utiliser du CSS arbitraire dans une application Stripe?

Non. La prop css sur Box accepte des tokens nommés plutôt que des valeurs libres, plusieurs composants possèdent des préréglages qui ne peuvent être surchargés, et les contraintes de hiérarchie des composants limitent ce qui peut contenir quoi. C'est délibéré — cela empêche des milliers d'applications tierces de rendre le Dashboard incohérent.

Dois-je personnaliser Stripe Elements avec des variables ou des règles?

Les variables d'abord, toujours. Elles se propagent sur l'ensemble de l'Element et restent correctes lorsque Stripe met à jour l'interne. Ne passez aux rules que pour des éléments que les variables ne peuvent véritablement pas exprimer, car chaque règle que vous écrivez est un sélecteur dont vous devenez responsable face aux futures modifications du markup.

Qu'est-ce que spacingUnit modifie réellement dans Stripe Elements?

C'est la valeur de base dont dérive tout le reste de l'espacement dans l'Element ; l'augmenter ou la diminuer rend donc l'ensemble du composant uniformément plus ou moins espacé sans rien toucher d'autre. Il s'agit d'un curseur unique plutôt que d'une liste d'espacements codés en dur, ce qui est le modèle qu'il convient de copier dans votre propre couche de tokens.