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 o motivo 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 apenas 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 entre milhares de apps de terceirosIntegração fluida 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 a sua UI está na superfície da Stripe, a Stripe não pode permitir que um app de terceiros com estilo ruim faça o Dashboard parecer quebrado, então ela remove essa capacidade. Quando a UI da Stripe está na sua superfície, um formulário de pagamento que ignora o seu design pareceria um problema de segurança, então a Stripe entrega o controle. Mesma empresa, mesmos valores de design, padrões opostos — porque a pergunta não é "como isso deve parecer", mas "quem é o responsável pela 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 válvula de escape para 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 consiste em sete níveis e um zero, documentados com valores fixos em pixels: xxsmall 2px, xsmall 4px, small 8px, medium 16px, large 24px, xlarge 32px, xxlarge 48px. O dimensionamento é fracionário — metades, terços, quartos, quintos, sextos, doze avos, além de fill — com opções de min, max e fit baseadas no conteúdo.

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

A parte interessante é o que acontece acima do Box. Componentes que não são 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 nos callbacks que implementa não permitirá que você contradiga isso, pois a aparência carrega um significado. Outros expõem um pequeno enum: o Button possui primary, padrão e destructive, e essa é a lista completa. Alguns poucos expõem uma única propriedade, como o Icon que aceita fill.

Existe também um conjunto documentado de restrições de hierarquia de componentes — regras sobre quais componentes podem conter quais. Esse é o equivalente de layout para a mesma ideia: não é um conselho sobre boa estrutura, mas uma restrição que faz com que estruturas ruins falhem em vez de serem publicadas.

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, em seguida, entrega uma prop className que aceita qualquer coisa; seis meses depois, metade da base de código tem valores hexadecimais arbitrários porque alguém estava com pressa em uma sexta-feira.

O Stripe Apps remove essa opção. Não existe caminho entre "estar com pressa" e #3c82f6, porque a prop não aceitará esse valor. Essa é uma garantia muito mais forte do que uma regra de linting 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 — ou seja, todos eles — este é o caminho.

É também a abordagem com o custo mais alto, e é justo ser honesto sobre isso. Um vocabulário fechado significa que cada requisito genuinamente novo se torna uma solicitação aos 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 é uma única pessoa mantendo um sistema para quatro squads de produto que têm prazos a cumprir.

Elements: a escada de três níveis

A Appearance API resolve o problema oposto. Um formulário de pagamento precisa parecer nativo em um site que ninguém na Stripe jamais viu, mantendo, ao mesmo tempo, 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 orienta você a subi-la em ordem.

  1. 1

    Escolha um tema

    Três pontos de partida pré-configurados — stripe, night, flat. Uma linha de código, e a maioria das integrações que precisam apenas de "não conflitar" resolvem-se 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 ocorre 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 for necessário

    Um mapeamento de seletores semelhantes a CSS para propriedades CSS, alcançando componentes e estados individuais. Esta é a válvula de escape, e está deliberadamente por último.

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

A ordenação é o design. Cada degrau é mais poderoso e mais caro de manter do que o anterior, e a documentação empurra você para baixo na escada, em vez de para cima. Uma equipe que começa pelas rules escreve quarenta seletores e se torna dona deles para sempre; uma equipe que começa pelo 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 por serem bases derivadas em vez de valores. O spacingUnit é descrito como a unidade base da qual todo o outro espaçamento deriva — aumente-o e todo o componente se torna mais espaçoso. O fontSizeBase define o tamanho raiz, e as outras variáveis de tamanho de fonte escalam a partir dele 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 controle ajustável. Se um cliente precisa de um formulário mais denso, a versão derivada requer a alteração de um único número; a versão enumerada requer doze edições e uma decisão subjetiva para 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 sejam 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 funcionam assim: nelas, cada passo precisa ser escolhido a olho.

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 sem glamour, e publicá-las é a decisão correta. Uma API de customização que falha silenciosamente em um subconjunto de entradas custa ao integrador uma tarde de depuração confusa; uma que avisa isso na tabela custa trinta segundos. Se o seu próprio sistema tem uma regra que só funciona em alguns lugares, a documentação é onde isso deve estar, não no changelog.

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

Ambos os sistemas foram projetados para desenvolvedores humanos lendo documentação. A pergunta 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 pegar atalhos em uma sexta-feira, mas também não tem memória das suas convenções entre sessões. Dê a ele um vocabulário fechado e ele usará esse 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 com a mesma frequência que os dados de treinamento usam — ou seja, às vezes.

Amostramos 299 arquivos DESIGN.md publicados para leitura de agentes de IA. 86% especificavam cores como valores hexadecimais brutos sem nenhum papel semântico atribuído, e 76% não continham proibição alguma. Esses dois números descrevem um arquivo que diz ao modelo quais cores existem, mas nada sobre o que elas significam ou o que é proibido — exatamente o oposto de ambos os sistemas da Stripe, que tratam quase inteiramente de significado e restrição.

O que o modelo faz com isso
Primary: #0570deUsa onde quer que o azul pareça razoável — cabeçalhos, 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 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 o limite. 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 admin 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, responsáveis diferentes pelo visual.

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 o componente inteiro uniformemente mais ou menos espaçoso sem tocar em mais nada. É um ajuste único em vez de uma lista de gaps hard-coded, que é o padrão que vale a pena copiar para sua própria camada de tokens.