Design tokens: o que são e como contribuem para a acessibilidade

Se você já tentou criar um projeto acessível e percebeu como pode ser desafiador manter cores, espaçamentos e tipografia sempre alinhados, este artigo é para você.
Design tokens ajudam a padronizar estilos e manter a harmonia visual do projeto. Com eles, é possível armazenar valores reutilizáveis, como cores, espaçamentos e tamanhos de fontes, criando um sistema visual bem estruturado e mais fácil de adaptar caso necessário.
Além disso, design tokens também facilitam a escalabilidade do projeto mantendo a consistência entre plataformas e melhoram a manutenção do código a longo prazo.
Outro ponto importante é que eles também contribuem para a acessibilidade, garantindo uma experiência mais inclusiva.
No desenvolvimento para web, a acessibilidade depende de boas práticas no design: um contraste bem ajustado, tamanhos de texto apropriados e espaçamentos bem distribuídos fazem toda a diferença para a experiência da pessoa usuária.
Agora, você deve estar se perguntando: "Ok, mas como colocar isso em prática?"
O Styled Components é um grande amigo nesse processo, ele faz com que possamos organizar design tokens de forma prática, centralizando estilos e adaptando temas conforme a necessidade do nosso projeto.
Neste artigo, vamos explorar:
- O que são design tokens e porque são úteis;
- Como eles contribuem para acessibilidade;
- Configuração de um sistema de temas, incluindo suporte a modo escuro;
- E mais!
Tudo isso com exemplos práticos para você testar no seu projeto. Então, aperte o cinto e vamos nessa!
O que são design tokens?
Design tokens são valores reutilizáveis que definem cores, tamanhos de fonte, espaçamentos, bordas e sombras em um projeto.
Em vez de espalhar esses valores pelo código, eles ficam guardados em um único lugar.
Mas aí você pode se perguntar “Por que usar isso? Não vai dar mais trabalho?”.
Vamos lá, imagina que precisamos mudar a cor principal dos botões do nosso projeto e ele já está bem grande.
Se essa cor estiver escrita diretamente em vários arquivos (exemplo: #007AFF), vamos precisar buscar e alterar em cada lugar em que for necessário, olha o trabalhão!
E se depois precisar mudar o tamanho de uma fonte? Lá vamos nós de novo procurar e alterar isso em muitos lugares, isso pode deixar o código confuso e trabalhoso de atualizar.
Com design tokens, cores, tamanhos de fonte, dentre outros, são definidas em um único lugar, e todas as partes do código que fazem referência a elas são atualizadas automaticamente.
Assim conseguimos evitar que, por algum engano, esqueçamos de mudar em um lugar do projeto.
Nesse artigo iremos utilizar um projeto simples para exemplificar o uso de design tokens e styled components.
Se você quiser conferir o projeto completinho com passo a passo para rodar na sua máquina, pode ver no repositório no GitHub.
Vamos ver um exemplo de organização de tokens?
Por questão de organização e boas práticas, iremos separar por arquivos. Então vamos criar uma pasta theme
, dentro do src
e nela vamos adicionar os arquivos dividindo-os por responsabilidades.
O arquivo colors.js
, onde vamos colocar todas as cores do projeto organizadas por tokens. Ou seja, em vez de usar valores fixos, teremos nomes que representam essas cores.
Assim, sempre que precisarmos de uma cor, basta chamar o token
correspondente, por exemplo: blue100
, blue200
e assim por diante, como mostro abaixo:
export const colors = {
blue100: "#005BBB",
blue200: "#007AFF",
gray100: "#F0F0F0",
gray200: "#B3B3B3",
black: "#1A1A1A",
white: "#FFFFFF",
yellow100: "#E69500",
yellow200: "#FFC300",
transparent: "transparent"
};
O arquivo breakpoints.js
, onde definiremos os pontos de quebra, para que o site seja responsivo.
export const breakpoints = {
small: "600px",
medium: "960px",
large: "1280px",
extraLarge: "1920px"
};
export const media = {
small: `@media (min-width: ${breakpoints.small})`,
medium: `@media (min-width: ${breakpoints.medium})`,
large: `@media (min-width: ${breakpoints.large})`,
extraLarge: `@media (min-width: ${breakpoints.extraLarge})`
};
E theme.js
onde teremos a estrutura central de temas, que inclui a importação dos arquivos colors.js
, breakpoints.js
e a definição dos dois temas que teremos: claro e escuro.
import { colors } from "./colors";
import { breakpoints, media } from "./breakpoints";
export const lightTheme = {
breakpoints,
media,
typography: {
fontSize: {
title: "clamp(1.25rem, 1.5vw, 1.5rem)",
subtitle: "clamp(1rem, 1.2vw, 1.125rem)",
body: "clamp(0.875rem, 1vw, 1rem)"
},
fontFamily: {
primary: "sans-serif",
secondary: "serif"
}
},
colors: {
background: {
primary: colors.gray100,
secondary: colors.white
},
text: {
title: colors.black,
body: colors.black,
placeholder: colors.gray200,
button: colors.white
},
primary: colors.blue100,
secondary: colors.blue200,
focus: colors.yellow100,
disabled: colors.gray100,
transparent: colors.transparent
},
padding: {
small: "0.5rem",
medium: "1rem",
large: "1.5rem"
},
margin: {
small: "0.5rem",
medium: "1rem",
large: "1.5rem"
},
gap: {
small: "0.5rem",
medium: "1rem",
large: "1.5rem"
},
borderWidth: {
thin: "1px",
thick: "2px"
},
borderRadius: {
small: "4px",
medium: "8px"
},
boxShadow: {
soft: `0px 2px 4px ${colors.black}1A`,
medium: `0px 4px 8px ${colors.black}26`,
strong: `0px 6px 12px ${colors.black}33`
}
};
export const darkTheme = {
...lightTheme,
colors: {
background: {
primary: colors.black,
secondary: colors.black
},
text: {
title: colors.white,
body: colors.white,
placeholder: colors.gray100,
button: colors.white
},
primary: colors.blue200,
secondary: colors.blue100,
focus: colors.yellow200,
disabled: colors.gray200,
transparent: colors.transparent
}
};
Eita, muita coisa né? Mas não se preocupa, isso pode parecer muito código e mais trabalho no começo, mas, no final, vai te poupar um tempão.
Porque se você precisar alterar qualquer valor, como uma cor ou um tamanho de fonte, é só mudar uma vez, e o efeito será aplicado em todo o projeto.
Assim a facilidade para manter só aumenta e quando outra pessoa bater o olho no código da pasta theme
vai entender do que se trata e saberá que ali que precisa modificar, por exemplo a cor primária.

Acessibilidade e design tokens
Se tem uma coisa que pode transformar um design bonito em uma experiência realmente agradável e funcional, é a acessibilidade. E adivinha? Design tokens podem te ajudar bastante nisso!
Vamos começar pelo contraste, que é um dos pilares para garantir que todo mundo consiga enxergar os elementos da página sem dificuldade.
Se o texto e o fundo tiverem cores muito próximas, fica praticamente impossível de ler. E é aqui que entra o WCAG (Web Content Accessibility Guidelines), um conjunto de diretrizes que define níveis mínimos de contraste para garantir que a informação seja visível para a maioria das pessoas.
Ele serve como referência para pessoas designers e desenvolvedoras ao criar interfaces mais inclusivas.
As diretrizes do WCAG são divididas em três níveis: A, AA e AAA. O nível A cobre os requisitos mais básicos, enquanto o nível AA é o mais recomendado, pois equilibra acessibilidade e design.
Já o nível AAA é mais rigoroso e pode ser difícil de aplicar em todos os projetos.
Um dos aspectos mais conhecidos do WCAG é o contraste de cores, o nível AA exige um contraste mínimo de 4.5:1 para textos normais e 3:1 para textos maiores. Isso garante que a leitura fique mais confortável, especialmente para pessoas com daltonismo ou baixa visão.
E, as diretrizes incluem recomendações sobre o uso de textos alternativos para imagens (ALTs), navegação acessível pelo teclado e a possibilidade de ajustar tamanhos de fonte sem comprometer a usabilidade.
Para quem desenvolve interfaces, o WCAG pode servir como um guia prático para evitar barreiras desde o início do projeto.
Se você tiver curiosidade, existem alguns sites que ajudam a testar a acessibilidade, uma delas é o Contrast Checker.
Também é possível usar o polished.js, que oferece funções super bacanas como getContrast()
e getLuminance()
. A função getContrast()
retorna a taxa de contraste entre duas cores, ajudando a verificar se elas atendem os padrões recomendados pelo W3C, a organização que desenvolve as diretrizes do WCAG.
Já getLuminance()
retorna um número representando a luminância de uma cor, esse valor pode ser usado para comparar cores e escolher automaticamente aquela com melhor visibilidade. Legal, né?
Se você quiser ler mais sobre, instalação, uso etc., recomendo a leitura da documentação que é bem completa, com muitos exemplos.
Agora, bora falar de tamanhos de fonte! Sabe quando você acessa um site no celular e o texto parece minúsculo?

Isso acontece quando os tamanhos das fontes não são escaláveis. Para evitar esse problema, podemos usar unidades relativas como rem
e em
, e a função clamp(), que permite definir um intervalo de tamanho mínimo e máximo para que a fonte se adapte melhor aos diferentes tamanhos de tela.
No nosso tema, já deixamos isso pronto:
fontSize: {
title: "clamp(1.25rem, 1.5vw, 1.5rem)",
subtitle: "clamp(1rem, 1.2vw, 1.125rem)",
body: "clamp(0.875rem, 1vw, 1rem)"
},
Assim, garantimos que os títulos, subtítulos e textos tenham tamanhos responsivos sem precisar ajustar manualmente para cada dispositivo.
E o espaçamento? Pois é, uma página sem espaçamentos bem definidos pode virar um verdadeiro pesadelo visual. Botões colados, textos apertados... ninguém merece!
Para resolver isso, usamos tokens de espaçamento bem arrumadinhos. Definimos margens
, paddings
e gaps
dentro do nosso tema para que o layout fique sempre bonitinho e confortável para leitura.
padding: {
small: "0.5rem",
medium: "1rem",
large: "1.5rem"
},
margin: {
small: "0.5rem",
medium: "1rem",
large: "1.5rem"
},
gap: {
small: "0.5rem",
medium: "1rem",
large: "1.5rem"
},
Fazendo desse jeito, evitamos layouts inconsistentes e melhora bastante a experiência da pessoa usuária.
E então temos bordas e sombras, que não são apenas detalhes estáticos, mas também elementos que ajudam na acessibilidade.
Bordas bem definidas garantem que os componentes tenham separação clara, e sombras bem aplicadas criam hierarquia visual. Isso ajuda a destacar elementos interativos como botões e modais.
Nosso tema já contempla isso com tokens definidos:
borderRadius: {
small: "4px",
medium: "8px"
},
boxShadow: {
soft: `0px 2px 4px ${colors.black}1A`,
medium: `0px 4px 8px ${colors.black}26`,
strong: `0px 6px 12px ${colors.black}33`
}
};
Em vez de colocar sombras aleatórias no código, utilizamos esses tokens para manter a consistência e garantir que todos os elementos tenham um visual alinhado e acessível.
No fim das contas, adotar acessibilidade usando design tokens não é só uma questão de boas práticas, mas também uma forma de criar interfaces mais amigáveis e que respeitam a diversidade das pessoas usuárias.
E o melhor? Depois de configurar tudo direitinho, sempre que você quiser ajustar ou melhorar algo fica mais fácil, mesmo que o projeto cresça.
Se você quiser saber mais sobre como criar conteúdos acessíveis e transformar a experiência das pessoas usuárias, confira o artigo Dicas para criar um conteúdo acessível para o seu produto.
Implementação com styled components
Agora que entendemos a importância do design tokens, vamos ver como usá-los na prática com Styled Components.
O Styled Components
nos possibilita escrever estilos diretamente nos componentes utilizando JavaScript, sem precisar classes CSS separadas.
A principal vantagem é que os estilos ficam limitados a cada componente, evitando conflitos com outros estilos da aplicação.
Instalação do Styled Components
A instalação do styled-components é simples, basta rodar o seguinte comando no terminal:
# com npm
npm install styled-components
Ou
# com yarn
yarn add styled-components
Na documentação há outras dicas e formas de instalação.
Para que os estilos sejam aplicados corretamente em toda nossa aplicação, usaremos o ThemeProvider
do styled-components
, ele garante que todos os componentes tenham acesso aos valores definidos no tema.
Esse código precisa tá no ponto mais alto da nossa aplicação, ou seja, aquele que “envolve” todos os outros, então colocaremos no App.js
:
import React, { useState } from "react";
import { ThemeProvider as StyledThemeProvider } from "styled-components";
import { lightTheme, darkTheme } from "./theme/theme";
import GlobalStyle from "./theme/GlobalStyle";
import Button from "./components/Button";
import ToggleButton from "./components/ToggleButton";
import styled from "styled-components";
const AppContainer = styled.main`
background-color: ${({ theme }) => theme.colors.background.primary};
min-height: 100vh;
padding: ${({ theme }) => theme.padding.medium};
color: ${({ theme }) => theme.colors.text.body};
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.gap.medium};
`;
const ButtonContainer = styled.div`
display: flex;
gap: ${({ theme }) => theme.gap.medium};
justify-content: center;
`;
function App() {
const [isDarkMode, setIsDarkMode] = useState(false);
const theme = isDarkMode ? darkTheme : lightTheme;
const toggleTheme = () => setIsDarkMode(!isDarkMode);
return (
<StyledThemeProvider theme={theme}>
<GlobalStyle />
<AppContainer>
<ButtonContainer>
<ToggleButton onClick={toggleTheme}>
{isDarkMode ? "Mudar para tema claro" : "Mudar para tema escuro"}
</ToggleButton>
<Button>Botão acessível</Button>
</ButtonContainer>
</AppContainer>
</StyledThemeProvider>
);
}
export default App;
Aqui nesse código, o ThemeProvider
possibilita que a gente alterne entre os temas lightTheme
e darkTheme
. E, para garantir estilos consistentes, utilizamos GlobalStyle
para definir configurações globais:
import { createGlobalStyle } from "styled-components";
const GlobalStyle = createGlobalStyle`
body {
margin: 0;
padding: 0;
font-family: ${({ theme }) => theme.typography.fontFamily.primary};
background-color: ${({ theme }) => theme.colors.background.primary};
color: ${({ theme }) => theme.colors.text.body};
transition: all 0.3s ease-in-out;
}
`;
export default GlobalStyle;
E você sabe onde colocaremos o arquivo de GlobalStyle
? Isso mesmo, na pasta theme
onde já estão os outros arquivos relacionados ao tema.
Você já tá pegando o jeito!
Criando um botão acessível com tokens
Agora, vamos criar um botão acessível com tokens?

Já vimos que design tokens ajudam a estruturar o projeto, possibilitando que elementos como botões sigam um padrão definido, garantindo uniformidade no uso de cores, espaçamentos e tipografia.
Vamos criar dentro do src
uma pasta chamada Button
e dentro dela colocar o arquivo index.jsx
onde colocaremos o código:
import styled from "styled-components";
const Button = styled.button`
background-color: ${({ theme }) => theme.colors.secondary};
color: ${({ theme }) => theme.colors.text.button};
border: ${({ theme }) => theme.borderWidth.thin} solid ${({ theme }) => theme.colors.primary};
border-radius: ${({ theme }) => theme.borderRadius.small};
padding: ${({ theme }) => theme.padding.medium};
cursor: pointer;
transition: all 0.3s ease-in-out;
&:hover {
background-color: ${({ theme }) => theme.colors.secondary};
}
&:focus {
outline: 2px solid ${({ theme }) => theme.colors.focus};
outline-offset: 2px;
}
&:disabled {
background-color: ${({ theme }) => theme.colors.disabled};
cursor: not-allowed;
}
`;
export default Button;
Uma das facilidades do Styled Components
é a possibilidade de estilizar os elementos com base em props, como podemos ver no código acima. Isso significa que os estilos podem ser dinâmicos e adaptáveis, dependendo do tema ou das configurações passadas para o componente.
E, os design tokens
que definimos lá no início estão sendo aplicados diretamente aqui, como theme.colors.secondary
, theme.borderRadius.small
e theme.padding.medium
garantem que o botão siga um padrão visual consistente em toda a aplicação.
E a acessibilidade é pelo contraste no texto (theme.colors.text.button
) e pela visibilidade ao navegar com o teclado (outline
no :focus
).
O efeito hover
melhora a experiência da pessoa usuária ao indicar que o botão é interativo.
Usando essa estrutura, qualquer alteração na identidade visual pode ser feita diretamente no design tokens, sem a necessidade de modificar cada componente individualmente. E tudo isso deixa o código mais legível também.
Modo escuro com design tokens
Agora, vamos permitir que a pessoa usuária alterne entre os temas claro e escuro dinamicamente. E faremos isso criando um theme switcher (alternador de tema).
Primeiro, vamos criar um ThemeContext
para gerenciar o estado do tema, ele vai armazenar o estado do tema e fazer com que a aplicação saiba qual deles está ativo.
Criaremos uma pasta dentro de src
chamada context
, e dentro dela criaremos o arquivo ThemeContext.jsx
:
import React, { createContext, useState, useContext } from "react";
import { lightTheme, darkTheme } from "../theme/theme";
import { ThemeProvider as StyledThemeProvider } from "styled-components";
const ThemeContext = createContext();
export const useTheme = () => useContext(ThemeContext);
export const ThemeProvider = ({ children }) => {
const [isDarkMode, setIsDarkMode] = useState(false);
const toggleTheme = () => setIsDarkMode(!isDarkMode);
const theme = isDarkMode ? darkTheme : lightTheme;
return (
<ThemeContext.Provider value={{ theme, isDarkMode, toggleTheme }}>
<StyledThemeProvider theme={theme}>{children}</StyledThemeProvider>
</ThemeContext.Provider>
);
};
Nós criamos um contexto (ThemeContext
) e usamos useState
para controlar o tema. Quando a pessoa usuária alterna entre os modos, o estado muda e o ThemeProvider
aplica o tema correto na aplicação.
Bom demais, né?
Agora a gente precisa de um botão para fazer essa troca de temas. Vamos criar uma pasta dentro de components
chamada ToggleButton
e dentro dela colocaremos o arquivo index.jsx
import styled from "styled-components";
import Button from "../Button";
const ToggleButton = styled(Button)`
background-color: ${({ theme }) => theme.colors.background.primary};
color: ${({ theme }) => theme.colors.primary};
border: ${({ theme }) => theme.borderWidth.thin} solid ${({ theme }) => theme.colors.primary};
border-radius: ${({ theme }) => theme.borderRadius.small};
padding: ${({ theme }) => theme.padding.small};
&:hover {
background-color: ${({ theme }) => theme.colors.background.primary};
color: ${({ theme }) => theme.colors.primary};
}
`;
export default ToggleButton;
Nessa parte, usamos styled-components
para estilizar o botão e mais uma vez aplicamos os valores definidos no design tokens, como cores, espaçamentos e bordas.
Isso faz com que o botão siga a identidade visual da aplicação e se adapte automaticamente ao tema escolhido pela pessoa.
Vamos dá uma olhada no App.jsx
agora, já que criamos o ThemeContext
para gerenciar os temas e o ToggleButton
para alterná-los, para ver como tudo isso se encaixa nele.
function App() {
const { theme, isDarkMode, toggleTheme } = useTheme();
return (
<AppContainer theme={theme}>
<ButtonContainer>
<ToggleButton onClick={toggleTheme}>
{isDarkMode ? "Mudar para tema claro" : "Mudar para tema escuro"}
</ToggleButton>
<Button>Botão acessível</Button>
</ButtonContainer>
</AppContainer>
);
}
export default App;
Quando a pessoa usuária clica no botão, o ThemeProvider
alterna entre os tokens do tema claro e escuro, mudando os estilos sem precisar recarregar a página.
Agora, em vez de gerenciar diretamente o tema dentro do App.jsx
, usamos a context API com o ThemeContext
, isso tira a responsabilidade do App
de lidar com a lógica de alternância de tema, deixando-o focando apenas em exibir os componentes da interface.
Essa separação de responsabilidades é uma boa prática, pois mantém o código mais organizado. Ao final teremos esse resultado:

Conclusão
Parabéns por chegar até aqui!

Nós vimos como os design tokens deixam o projeto mais organizado e prático de usar. Com eles, dá para garantir que tudo fique sempre com a mesma cara, sem dor de cabeça na hora de atualizar ou adaptar para diferentes telas.
Outra coisa importante que vimos: acessibilidade não é algo que dá para deixar para depois. Quando já começamos pensando nisso, evitamos retrabalho e criamos algo que realmente funciona para todo mundo.
E agora, o próximo passo é integrar os tokens ao Storybook! Ele é usado para desenvolver e documentar componentes de forma isolada, ele possibilita a visualização e testes de componentes sem precisar rodar toda a aplicação.
Se quiser aprender mais sobre se liga nessa formação:
Bora seguir nessa evolução?
Referências
Como Design Tokens auxiliam na gestão de um Design System (português, gratuito, artigo): explicação sobre como os design tokens facilitam a manutenção e evolução de um Design System;
React: Desenvolvendo Design Tokens com Styled Components (português, pago, curso): curso da Alura sobre a criação e aplicação de design tokens em projetos React usando Styled Components;
Styled Components Documentation (inglês, gratuito, site): documentação oficial do Styled Components, cobrindo desde conceitos básicos até recursos avançados;
Acessibilidade na Web (português, gratuito, artigo): introdução aos princípios da acessibilidade digital e sua importância para tornar a web mais inclusiva;
Usabilidade e Acessibilidade: Qual a Diferença? (português, gratuito, artigo): explicação sobre as diferenças entre usabilidade e acessibilidade e como esses conceitos se complementam no design de interfaces;
Como Criar Conteúdo Acessível para Produtos Digitais (português, gratuito, artigo): orientações práticas para criar conteúdos digitais acessíveis e melhorar a experiência de diferentes públicos;
How We Use Design Tokens in React (inglês, gratuito, site): artigo explicando como os design tokens podem ser aplicados em projetos React para manter consistência visual;
Como usar Styled Components (português, gratuito, site): guia introdutório sobre o uso de Styled Components para estilização no React;
CSS Borders: Estilos, Design, Exemplos, Código e Dicas (português, gratuito, site): artigo abordando diferentes estilos de bordas no CSS, com exemplos práticos e dicas de aplicação.