Começar

Os dois design systems da Stripe e por que eles divergem

Se você procurar pelo design system da Stripe, encontrará pessoas buscando a coisa errada. O sistema interno da Stripe não é público. O que está publicado são dois sistemas voltados para o cliente que fazem apostas exatamente opostas sobre quem tem permissão para controlar os pixels, e a razão dessa divergência vale mais do que qualquer arquivo de tokens.

Atualizado 2026-07-27

Análise independente da documentação pública para desenvolvedores da Stripe, escrita para pessoas que estão projetando seus próprios sistemas. O Identity Forge não é afiliado nem endossado pela Stripe. Stripe e seu logotipo são marcas registradas de seu proprietário. Os detalhes aqui refletem a documentação no momento da redação; verifique em docs.stripe.com antes de basear-se em qualquer valor específico.

O que as pessoas estão procurando não existe publicamente

As superfícies de produto da própria Stripe (o Dashboard, o site de marketing, a documentação) rodam em um sistema interno que foi referido ao longo dos anos por vários nomes e nunca foi lançado como um pacote público. Não há npm install, nem Storybook, nem exportação de tokens. Se era isso que você procurava, não está disponível, e reconstruções de terceiros são inferências baseadas em screenshots.

O que a Stripe publica, e documenta minuciosamente, são dois sistemas voltados para desenvolvedores que integram com a Stripe. Eles geralmente são discutidos separadamente porque estão em cantos diferentes da documentação. Lidos juntos, eles são uma pequena masterclass em limites de design system.

Stripe Apps UI toolkitElements Appearance API
Onde a UI é renderizadaDentro do Stripe DashboardDentro do seu produto
Qual marca governaA da StripeA sua
CSS arbitrárioNão é possível. A prop css aceita apenas tokensSuportado, via mapa de rules
EspaçamentoSete etapas nomeadas e fixasUm spacingUnit definido por você; tudo deriva dele
Estilização de componentesPredefinida; alguns componentes recusam totalmente a sobrescritaCustomizável via temas até seletores e estados individuais
O que ele otimizaConsistência em milhares de apps de terceirosIntegração em um checkout que você não projetou
Dois sistemas públicos da Stripe, duas posturas opostas.

A linha entre eles não é técnica. É um limite de confiança. Quando sua UI reside na superfície da Stripe, a Stripe não pode permitir que um app de terceiro mal estilizado faça o Dashboard parecer quebrado, por isso ela remove essa capacidade. Quando a UI da Stripe reside na sua superfície, um formulário de pagamento que ignore o seu design pareceria um problema de segurança, então a Stripe entrega o controle a você. Mesma empresa, mesmos valores de design, padrões opostos, porque a questão não é "como isso deve parecer", mas sim "quem é o responsável por sua aparência".

Stripe Apps: um design system imposto pela assinatura de tipo

O toolkit de UI do Stripe Apps oferece um conjunto de componentes (views, layout, navegação, conteúdo, formulários, gráficos), além de uma primitiva Box com uma prop css. A prop css parece uma saída de emergência de estilização, mas não é. Ela aceita tokens nomeados, e nada mais.

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

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

O vocabulário de espaçamento possui sete etapas e um zero, documentado com valores fixos em pixels: xxsmall 2px, xsmall 4px, small 8px, medium 16px, large 24px, xlarge 32px, xxlarge 48px. O dimensionamento é fracionado (metades, terços, quartos, quintos, sextos, doze avos, além de fill) com opções de min, max e fit baseadas no conteúdo.

Note as proporções nessa escala de espaçamento. Ela não é linear (2, 4, 8, 16, 24, 32, 48): ela dobra no extremo inferior, onde diferenças de 2px são visíveis, e depois avança de 8 em 8 no extremo superior, onde não são. Uma escala que dobra até chegar a 128 desperdiça etapas que ninguém usa; uma que avança de 4 em 4 o caminho todo oferece treze valores que parecem todos iguais.

A parte interessante é o que acontece acima do Box. Componentes que não sejam Box ou Inline possuem estilos predefinidos, e a documentação é explícita ao dizer que alguns deles não podem ser sobrescritos de forma alguma: um componente que muda de aparência com base em quais callbacks ele implementa não permitirá que você o contradiga, pois a aparência carrega significado. Outros expõem um pequeno enum: Button possui primary, default e destructive, e essa é a lista completa. Alguns expõem apenas uma propriedade, como o Icon aceitando fill.

Existe também um conjunto documentado de restrições de hierarquia de componentes: regras sobre quais componentes podem conter quais. Isso é o equivalente de layout da mesma ideia: não é um conselho sobre boa estrutura, mas uma restrição que faz uma estrutura ruim falhar em vez de ser implementada.

A lição: a imposição vence a documentação

Quase todo design system é um projeto de documentação. Ele diz para usar os tokens e, depois, entrega uma prop className que aceita qualquer coisa, e seis meses depois metade do codebase tem valores hex arbitrários porque alguém estava com pressa em uma sexta-feira.

O Stripe Apps remove essa opção. Não há caminho de "estar com pressa" para #3c82f6, porque a prop não aceitará isso. Isso é uma garantia muito mais forte do que uma regra de lint e infinitamente mais forte do que um parágrafo em uma wiki. Se você mantém um sistema que precisa sobreviver a contribuidores que não leram a documentação — que são todos eles — este é o caminho.

Este também é o caminho com o maior custo, e vale a pena ser honesto sobre isso. Um vocabulário fechado significa que cada novo requisito genuíno se torna uma solicitação para os proprietários do sistema. Isso é tolerável quando os proprietários são uma equipe de plataforma financiada que atende a um marketplace de apps. É miserável quando se trata de uma única pessoa mantendo um sistema para quatro squads de produto que têm prazos a cumprir.

Elementos: a escada de três níveis

A Appearance API resolve o problema oposto. Um formulário de pagamento precisa parecer nativo de um site que ninguém na Stripe viu, ao mesmo tempo em que mantém um layout que a Stripe controla por razões de conversão e conformidade. A resposta da Stripe é uma escada com três degraus, e a documentação diz para você subí-la em ordem.

  1. 1

    Escolha um tema

    Três pontos de partida pré-construídos: stripe, night, flat. Uma linha, e a maioria das integrações que só precisam não conflitar já estão prontas aqui.

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

    Defina variáveis

    Um pequeno conjunto de valores que se propagam por toda parte. Esta é a camada de tokens, e é onde acontece a maior parte da customização real.

    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

    Adicione regras, apenas se ainda precisar

    Um mapeamento de seletores estilo CSS para propriedades CSS, alcançando componentes e estados individuais. Este é o escape hatch, e é deliberadamente o último.

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

A ordem é o design. Cada degrau é mais poderoso e mais caro de manter do que o degrau abaixo, e a documentação empurra você para baixo na escada, em vez de para cima. Uma equipe que começa em rules escreve quarenta seletores e é dona deles para sempre; uma equipe que começa em theme escreve uma linha e só desce quando realmente precisa.

spacingUnit é a ideia de design de tokens que vale a pena copiar

Entre as variáveis, duas merecem atenção porque são bases derivadas, em vez de valores. spacingUnit é descrita como a unidade base da qual todos os outros espaçamentos derivam: aumente-a e todo o componente se torna mais espaçoso. fontSizeBase define o tamanho raiz, e as outras variáveis de tamanho de fonte escalam a partir dela em rem.

Compare isso com a abordagem usual, onde um design system publica de --space-1 a --space-12 como doze valores independentes e fixos. Ambos oferecem uma escala. Apenas um oferece um seletor. Se um cliente precisar de um formulário mais denso, a versão derivada é um único número; a versão enumerada exige doze edições e uma decisão subjetiva em cada uma.

/* 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);

Isso vale a pena ser aplicado além do espaçamento. Qualquer escala onde os passos são genuinamente proporcionais (espaçamento, tipografia, raio) é melhor expressa como uma base mais uma proporção do que como uma lista. Escalas onde os passos não são proporcionais, como uma rampa de cores neutras, não são: essas precisam que cada passo seja escolhido visualmente.

As exceções documentadas são a parte honesta

A documentação da Appearance API afirma que colorPrimary, colorBackground, colorText, colorSuccess, colorDanger e colorWarning não suportam a sintaxe rgba() ou var(--myVariable), enquanto outras variáveis suportam. Também observa que a API não se aplica a Elements de métodos de pagamento individuais como o CardElement, que utilizam um objeto Style separado.

Essas são inconsistências pouco glamorosas, e publicá-las é a decisão correta. Uma API de customização que falha silenciosamente em um subconjunto de inputs custa ao integrador uma tarde de depuração confusa; uma que avisa isso na tabela custa a ele trinta segundos. Se o seu próprio sistema tem uma regra que só funciona em alguns lugares, a documentação é o lugar onde isso deve estar, não o changelog.

Aplicando ambos os padrões a um sistema voltado para agentes

Ambos os sistemas foram projetados para desenvolvedores humanos lendo documentação. A questão interessante em 2026 é o que muda quando o desenvolvedor é um agente de código, e a resposta é que a postura do Stripe Apps se torna mais forte, enquanto a postura do Elements se torna mais fraca.

Um agente não tem incentivo para cortar caminho em uma sexta-feira, mas também não tem memória de suas convenções entre sessões. Dê a ele um vocabulário fechado e ele usará o vocabulário, de forma confiável, para sempre. Dê a ele uma prop className e um parágrafo dizendo "prefira os tokens" e ele usará os tokens aproximadamente com a mesma frequência que os dados de treinamento, o que quer dizer, às vezes.

Amostramos 299 arquivos DESIGN.md publicados para leitura de agentes de IA. 86% especificavam cores como valores hex brutos, sem nenhum papel semântico associado, e 76% não continham nenhuma proibição. Esses dois números descrevem um arquivo que diz a um modelo quais cores existem e nada sobre o que elas significam ou o que é proibido: o exato oposto de ambos os sistemas da Stripe, que são quase inteiramente sobre significado e restrição.

O que o modelo faz com isso
Primary: #0570deUsa onde o azul parece razoável: títulos, links, bordas, um gradiente
--color-primary: #0570de: apenas para ações primárias e estado ativo. Nunca para texto, bordas ou fundos.Usa em ações primárias e no estado ativo. A proibição é o que faz a diferença
Spacing: 4, 8, 12, 16, 24, 32Usa majoritariamente estes; ocasionalmente emite 14px ou 20px quando o layout está apertado
Spacing scale is xs/sm/md/lg/xl only. Any other value is a bug.Mantém-se na escala, porque o arquivo definiu o que é considerado errado
A mesma orientação, escrita como uma lista de valores e escrita como um vocabulário.

Essa é a ideia do Stripe Apps transposta para prosa: você não pode dar um erro de tipo a um agente, mas pode dizer a ele o que seria um. A ideia do Elements também se transfere como uma ordenação: declare primeiro os padrões do nível de tema, depois os tokens e, por fim, as exceções específicas, para que um modelo que leia de cima para baixo encontre a regra geral antes do caso especial.

Os design kits do Identity Forge são construídos exatamente com essa estrutura: papéis semânticos em vez de hexadecimais puros, uma lista explícita de 'faça e não faça' e motivos que descrevem o que o design faz, em vez de quais valores ele contém. Explore os kits ou comece por o que é um arquivo DESIGN.md.

O que extrair disso

A maioria das equipes que constroem um design system escolhe uma postura e a aplica em todo lugar. A documentação da Stripe é uma demonstração de que a postura deve seguir a fronteira. Em superfícies pelas quais você é responsável, feche o vocabulário e torne as violações impossíveis. Em superfícies pelas quais outra pessoa é responsável, publique uma escada e deixe que subam apenas até onde for necessário.

A maioria dos produtos possui ambos os tipos de superfície. A ferramenta de administração interna e o widget incorporável não são o mesmo problema de design, e um sistema único com uma única estratégia de customização atenderá mal a um deles.

Posso baixar o design system da Stripe?

Não o interno usado para o Dashboard e o site de marketing. Ele nunca foi publicado como um pacote ou site de documentação. O toolkit de UI do Stripe Apps e a Appearance API do Elements são públicos e documentados, mas são sistemas para integração com a Stripe, não para construir seu próprio produto.

Qual a diferença entre o Stripe Elements e o toolkit de UI do Stripe Apps?

O Elements é a UI de pagamentos da Stripe que você incorpora em seu site, estilizada para combinar com sua marca através da Appearance API. O toolkit de UI do Stripe Apps é uma biblioteca de componentes para construir apps que renderizam dentro do Dashboard da Stripe, estilizada para combinar com a marca da Stripe, sem possibilidade de override. Superfícies diferentes, proprietários da estética diferentes.

Posso usar CSS arbitrário em um Stripe App?

Não. A prop css no Box aceita tokens nomeados em vez de valores livres, vários componentes possuem presets que não podem ser alterados e restrições de hierarquia de componentes limitam o que pode conter o quê. Isso é deliberado. Evita que milhares de apps de terceiros tornem o Dashboard inconsistente.

Devo customizar o Stripe Elements com variáveis ou regras?

Variáveis primeiro, sempre. Elas se propagam por todo o Element e permanecem corretas quando a Stripe atualiza o internals. Recorra a rules apenas para algo que as variáveis genuinamente não consigam expressar, pois cada regra que você escreve é um seletor que agora você precisa manter contra futuras mudanças de markup.

O que o spacingUnit realmente altera no Stripe Elements?

Ele é o valor base do qual todo o outro espaçamento no Element deriva; portanto, aumentá-lo ou diminuí-lo torna todo o componente uniformemente mais ou menos espaçoso sem tocar em mais nada. É um ajuste único em vez de uma lista de gaps fixos, que é o padrão que vale a pena copiar para sua própria camada de tokens.