Dashboards e gráficos acessíveis para e-commerce: do KPI ao gráfico+tabela
Um board executivo responde à decisão em segundos, é legível por leitor de tela e não esconde nada atrás de cor, pizza ou gauge.
Alexandre Caramaschi
CEO da Brasil GEO, ex-CMO da Semantix (Nasdaq), cofundador da AI Brasil
Um board de e-commerce não existe para impressionar; existe para decidir. O teste de um bom painel é cruel e simples: o executivo olha por cinco segundos e responde “estamos bem ou mal, em relação a quê, e o que mudou?”. Se ele precisa interpretar um gauge floreado ou medir ângulos de uma pizza, o painel falhou. Pior: se metade da equipe não enxerga a cor que carrega a informação, o painel exclui gente.
Este guia mostra como montar um decision cockpit de e-commerce que responde rápido, é legível por leitor de tela e não esconde nada atrás de cor ou de gráfico decorativo. Ele aprofunda a base lançada no guia de design system e CSS moderno.
Por que o board começa pela pergunta de decisão, não pelo gráfico?
Resposta direta: porque o gráfico é meio, não fim. O inimigo número um de um painel é a vaidade visual: pizza, gauge e 3D ocupam espaço e comunicam pouco. A pizza obriga o olho a comparar ângulos, tarefa em que ele é ruim; o gauge gasta um quadrante inteiro para mostrar um número que um texto resolveria. A regra é trocar pizza por barras (comparação entre categorias) e gauge por bullet chart (meta vs realizado).
Os três KPIs abaixo seguem essa disciplina. Cada um responde às três perguntas de uma vez: o valor diz como estamos, o delta com seta e sinal diz o que mudou, e o bullet diz em relação a qual meta.
Receita 30 dias
R$ 1,24 mi
▲ 8,2%Margem de contribuição
38%
▲ 2,1 p.p.Ruptura de estoque
6,4%
▼ 1,9 p.p. Fora da metaComo mostrar uma tabela de variância que todos conseguem ler?
Resposta direta: com uma tabela HTML semântica, números alinhados à direita e a variância marcada por cor mais sinal, nunca só por cor. A tabela de variância é a espinha de qualquer board de resultado, e a tag <table> entrega acessibilidade de graça: o leitor de tela navega linhas e colunas, anuncia os cabeçalhos e associa cada número à sua métrica.
| Métrica | Realizado | Meta | Variância (%) |
|---|---|---|---|
| Receita | R$ 1.240.000 | R$ 1.000.000 | +24% |
| Ticket médio | R$ 312 | R$ 300 | +4% |
| Conversão | 1,8% | 2,2% | −18,2% |
| Ruptura de estoque | 6,4% | 4% | +60% |
A regra inegociável é não substituir essa tabela por uma grade de <div>s estilizados. A grade pode parecer idêntica, mas é muda para a tecnologia assistiva. Os detalhes que tornam a tabela acima legível para todos:
<table>
<caption>Resultado vs meta — trimestre</caption>
<thead>
<tr>
<th scope="col">Métrica</th>
<th scope="col">Realizado</th>
<th scope="col">Meta</th>
<th scope="col">Variância (%)</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Receita</th>
<td class="num">R$ 1.240.000</td>
<td class="num">R$ 1.000.000</td>
<td class="num var-up">▲ +24%</td>
</tr>
</tbody>
</table>
Note quatro decisões: <th scope="col"> e <th scope="row"> amarram cada célula ao seu cabeçalho; os números ficam alinhados à direita (text-align: right) para comparação visual de colunas; a variância carrega seta, sinal e cor juntos; e a cor vem de um token que passa em contraste AA (verde e vermelho de luminosidade alta sobre o fundo escuro), não de um vermelho-sangue que some no dark.
Quando trocar o SVG à mão por uma biblioteca?
Resposta direta: quando você precisa de uma série temporal com dezenas ou milhares de pontos, interatividade (tooltip, zoom, brush) ou tipos de gráfico complexos. Para KPI card, bullet, sparkline e barra simples, o SVG inline é mais leve e suficiente. Acima desse limite, a biblioteca compensa. Estas são as seis escolhas de 2026, cada uma com o seu ponto ótimo.
ECharts — o all-rounder (Canvas ou SVG), forte em datasets grandes e dashboards ricos.
import * as echarts from "echarts";
const chart = echarts.init(document.getElementById("vendas"));
chart.setOption({
xAxis: { type: "category", data: ["Jan", "Fev", "Mar", "Abr"],
axisLabel: { color: "#cbd5e1" } }, // rótulo com contraste AA, não o cinza padrão
yAxis: { type: "value", axisLabel: { color: "#cbd5e1" } },
tooltip: { trigger: "axis" },
series: [{ type: "line", smooth: true, data: [820, 932, 901, 1290] }],
});
Chart.js — o caminho mais rápido para um gráfico Canvas decente, com API enxuta.
import { Chart } from "chart.js/auto";
new Chart(document.getElementById("pedidos"), {
type: "bar",
data: { labels: ["Loja", "Marketplace", "PDV"], datasets: [{ label: "Pedidos", data: [540, 820, 210] }] },
options: { scales: { x: { ticks: { color: "#cbd5e1" } }, y: { ticks: { color: "#cbd5e1" } } } },
});
Plotly — científico e financeiro, traz zoom, pan e exportação prontos.
import Plotly from "plotly.js-dist-min";
Plotly.newPlot("receita", [{ x: ["Jan", "Fev", "Mar"], y: [820, 932, 901], type: "scatter", mode: "lines+markers" }],
{ font: { color: "#cbd5e1" }, margin: { t: 16 } });
visx — primitivas de baixo nível para React (camada fina sobre D3); você compõe o gráfico peça por peça, com controle total.
import { scaleLinear } from "@visx/scale";
import { LinePath } from "@visx/shape";
const x = scaleLinear({ domain: [0, 3], range: [0, 320] });
const y = scaleLinear({ domain: [0, 1300], range: [160, 0] });
// <svg width={320} height={160}>
// <LinePath data={pontos} x={(d) => x(d.i)} y={(d) => y(d.v)} stroke="currentColor" strokeWidth={2} />
// </svg>
Tremor — componentes de dashboard prontos para React, já estilizados com Tailwind; ótimo para sair do zero rápido.
import { LineChart } from "@tremor/react";
<LineChart
data={vendas}
index="mes"
categories={["receita"]}
valueFormatter={(n) => `R$ ${n.toLocaleString("pt-BR")}`}
/>
uPlot — ultraleve, feito para séries temporais enormes (milhares de pontos) com render quase instantâneo.
import uPlot from "uplot";
const opts = { width: 640, height: 240, series: [{}, { stroke: "#818cf8", label: "Sessões" }] };
new uPlot(opts, [tempos, valores], document.getElementById("trafego"));
A escolha não é religiosa: ECharts cobre a maioria dos dashboards; uPlot ganha quando o volume de pontos é o gargalo; Tremor acelera quem já vive em React e Tailwind; visx serve quem precisa de um gráfico sob medida. A régua completa de stacks está em como escolher a stack de frontend.
Como manter o gráfico legível para quem usa leitor de tela?
Resposta direta: com o padrão gráfico mais tabela. O gráfico desenha formas, não números narráveis; então o SVG (ou o canvas da biblioteca) fica aria-hidden, e uma tabela equivalente, escondida com sr-only, carrega os mesmos dados para a tecnologia assistiva. As barras abaixo trazem rótulo e valor visíveis (a informação não depende só de cor) e, logo após, uma tabela que só o leitor de tela percebe.
| Categoria | Valor |
|---|---|
| Loja própria | 540 |
| Marketplaces | 820 |
| PDV físico | 210 |
| Social commerce | 160 |
A técnica sr-only é um trecho de CSS que tira o elemento da tela sem removê-lo da árvore de acessibilidade. Ela é o oposto de display: none, e essa diferença é o ponto central.
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
Nunca esconda com
display: noneo que precisa ser lido por leitor de tela; isso remove o conteúdo de TODO mundo, inclusive de quem usa tecnologia assistiva. A técnicasr-onlyesconde só visualmente.
Dois erros que o gerador de código comete com frequência merecem atenção redobrada. O primeiro: rótulos de eixo no cinza claro padrão de muitas bibliotecas, que reprova no contraste; corrija sempre a cor dos ticks para um valor que passe AA nos dois temas. O segundo: informação que depende só de cor; toda série, todo delta, toda fatia precisa de rótulo, valor ou forma redundante, para que daltônicos e leitores de tela não fiquem de fora.
Quais são os critérios de sucesso de um board?
Resposta direta: um board está pronto quando passa nestes cinco testes objetivos.
- Nenhuma informação depende só de cor: todo delta tem seta e sinal, toda categoria tem rótulo.
- Existe alternativa em texto para cada gráfico, escondida com
sr-onlye legível por leitor de tela. - Zero pizza, gauge ou 3D; comparações em barras, meta vs realizado em bullet.
- Rótulos e eixos passam contraste AA nos dois temas (claro e escuro).
- O painel se reorganiza ao estreitar a janela sem quebrar a leitura, com container queries em vez de pontos de quebra globais.
Próximo passo
Pegue o painel que você usa hoje e aplique a régua: troque qualquer pizza por barras, qualquer gauge por bullet, e adicione a cada gráfico a sua tabela sr-only. Depois, padronize as cores por tokens com contraste AA, seguindo o guia de design system, tokens e CSS moderno. Para amarrar os números à estratégia de visibilidade, veja medição de visibilidade generativa (GEO) e, para a camada de dados por trás do board, data platform, CDP e resolução de identidade.
Perguntas frequentes
Por que não usar um gráfico de pizza ou um gauge no painel?
Resposta direta: porque ambos comunicam mal. A pizza obriga o olho a comparar ângulos, coisa que ele faz pior do que comparar comprimentos; o gauge gasta muito espaço para mostrar um único número. Troque pizza por barras e gauge por bullet chart: mesma informação, leitura imediata.
Como um leitor de tela entende um gráfico?
Resposta direta: não entende as formas; ele lê texto. Por isso o padrão é gráfico mais tabela: o SVG fica aria-hidden e uma tabela equivalente, escondida com a técnica sr-only, fica disponível para a tecnologia assistiva. Nunca use display:none nessa tabela, porque isso a removeria de todos.
O que é a técnica sr-only?
Resposta direta: é um trecho de CSS que tira o elemento da tela sem removê-lo da árvore de acessibilidade. O conteúdo continua sendo narrado pelo leitor de tela, mas não ocupa espaço visual. Frameworks como o Tailwind já trazem a classe sr-only pronta.
Quando vale a pena usar uma biblioteca de gráficos em vez de SVG à mão?
Resposta direta: quando a série tem dezenas ou milhares de pontos, precisa de tooltip, zoom ou brush, ou usa tipos complexos. Para KPI card, bullet, sparkline e barra simples, o SVG inline é mais leve e suficiente. Acima disso, entram ECharts, Chart.js, Plotly, visx, Tremor ou uPlot.
Como garantir contraste nos rótulos do gráfico?
Resposta direta: não confie no cinza claro padrão de muitas bibliotecas. Defina a cor dos rótulos de eixo por um token que passe no contraste AA nos dois temas, e garanta que toda informação tenha rótulo, valor ou forma redundante, nunca apenas cor.
Para levar deste guia
-
Um board começa pela pergunta de decisão (bem ou mal, vs o quê, o que mudou), não pelo gráfico bonito; pizza, gauge e 3D são anti-padrão.
-
Realizado vs meta se lê melhor num bullet chart que num gauge; comparação entre categorias se lê melhor em barras que em pizza.
-
Tabela de variância usa <table> semântica (th scope, números à direita, AA) e marca a variância com cor mais sinal, nunca só cor.
-
Gráfico não é narrável por leitor de tela: o padrão robusto é gráfico visual (aria-hidden) mais tabela equivalente escondida com sr-only.
-
SVG à mão para o simples; biblioteca (ECharts, Chart.js, Plotly, visx, Tremor, uPlot) só quando há séries densas, interatividade e tooltips.