Tabela

Passa columns e rows e a tabela constrói-se sozinha, cabeçalho incluído. Vai envolvida num contentor com deslocamento horizontal, por isso uma tabela com mais colunas do que um telemóvel mostra desliza sozinha em vez de esticar a página. Exportada como table e como dataTable.

Tabela básica

PáginaTamanhoTempo de render
/4,1 kB12 ms
/docs12,7 kB31 ms
/examples9,4 kB24 ms
table({
  columns: [
    { key: 'page', header: 'Página' },
    { key: 'size', header: 'Tamanho' },
    { key: 'time', header: 'Tempo de render' },
  ],
  rows: [
    { page: '/', size: '4,1 kB', time: '12 ms' },
    { page: '/docs', size: '12,7 kB', time: '31 ms' },
    { page: '/examples', size: '9,4 kB', time: '24 ms' },
  ],
})

Alinhamento

Os números leem-se melhor alinhados ao fim da sua coluna.

PáginaBytesGzip
/4 1121 204
/docs12 7043 910
/examples9 3882 744
table({
  columns: [
    { key: 'page', header: 'Página' },
    { key: 'bytes', header: 'Bytes', align: 'end' },
    { key: 'gzip', header: 'Gzip', align: 'end' },
  ],
  rows: [
    { page: '/', bytes: '4 112', gzip: '1 204' },
    { page: '/docs', bytes: '12 704', gzip: '3 910' },
    { page: '/examples', bytes: '9 388', gzip: '2 744' },
  ],
})

Células à medida

Uma coluna com uma função render recebe a linha inteira e devolve o que deve ficar na célula — um chip, uma ligação, um número formatado.

PáginaTamanhoEstado
/docs/routing18,2 kBok
/docs/data21,7 kBok
/docs/islands24,1 kBfalhou
table({
  columns: [
    { header: 'Página', render: (row) => link({ href: row.href }, row.page) },
    { key: 'size', header: 'Tamanho', align: 'end' },
    { header: 'Estado', align: 'end', render: (row) =>
      chip({ size: 'sm', dot: true, color: row.ok ? 'success' : 'danger' }, row.ok ? 'ok' : 'falhou') },
  ],
  rows: [
    { page: '/docs/routing', href: '/pt/docs/routing', size: '18,2 kB', ok: true },
    { page: '/docs/data', href: '/pt/docs/data', size: '21,7 kB', ok: true },
    { page: '/docs/islands', href: '/pt/docs/islands', size: '24,1 kB', ok: false },
  ],
})

Estilos

striped pinta linhas alternadas, hover realça a linha sob o ponteiro, e dense aperta o espaçamento para uma tabela com muitas linhas.

às riscas
NomeValor
páginas169
recursos208
total9,5 MB
com realce e densa
NomeValor
páginas169
recursos208
total9,5 MB
stack({ gap: 'lg' },
  table({
    striped: true,
    caption: 'às riscas',
    columns: [{ key: 'name', header: 'Nome' }, { key: 'value', header: 'Valor', align: 'end' }],
    rows: [{ name: 'páginas', value: '169' }, { name: 'recursos', value: '208' }, { name: 'total', value: '9,5 MB' }],
  }),
  table({
    hover: true,
    dense: true,
    caption: 'com realce e densa',
    columns: [{ key: 'name', header: 'Nome' }, { key: 'value', header: 'Valor', align: 'end' }],
    rows: [{ name: 'páginas', value: '169' }, { name: 'recursos', value: '208' }, { name: 'total', value: '9,5 MB' }],
  }),
)

Legenda

Uma legenda dá nome à tabela para quem chega a ela sem o texto à volta — vale a pena sempre que a tabela não esteja logo abaixo de um cabeçalho que já diga o que é.

Saída das construções, a mais recente primeiro
CommitQuandoPáginas
94a837ahá 4 minutos169
dcfaaaehá 2 horas161
table({
  caption: 'Saída das construções, a mais recente primeiro',
  columns: [
    { key: 'commit', header: 'Commit' },
    { key: 'when', header: 'Quando' },
    { key: 'pages', header: 'Páginas', align: 'end' },
  ],
  rows: [
    { commit: '94a837a', when: 'há 4 minutos', pages: '169' },
    { commit: 'dcfaaae', when: 'há 2 horas', pages: '161' },
  ],
})

A partir de dados

As linhas são um array vulgar, por isso costumam ser aquilo que o data() já carregou — sem adaptador pelo meio.

ArtigoPublicadoLeituras
Olá mundo2026-01-141.204
Estático primeiro2026-02-02890
Sem runtime2026-03-192.317
return (() => {
  const posts = [
    { title: 'Olá mundo', date: '2026-01-14', reads: 1204 },
    { title: 'Estático primeiro', date: '2026-02-02', reads: 890 },
    { title: 'Sem runtime', date: '2026-03-19', reads: 2317 },
  ]

  return table({
    hover: true,
    columns: [
      { key: 'title', header: 'Artigo' },
      { key: 'date', header: 'Publicado' },
      { header: 'Leituras', align: 'end', render: (post) => post.reads.toLocaleString('pt') },
    ],
    rows: posts,
  })
})()

Escrever a marcação à mão

Omite columns e a tabela desenha antes os seus filhos, por isso uma tabela com linha de rodapé ou cabeçalhos agrupados pode ser feita à mão e continuar a receber o estilo e o contentor com deslocamento.

Props

PropTipoPredefiniçãoDescrição
columnsTableColumn[]—{ key, header, align, render } por coluna. Omite para escreveres as linhas à mão.
rowsobject[][]Um objeto por linha.
captionChild—Uma legenda por cima da tabela.
stripedbooleanfalsePintar linhas alternadas.
hoverbooleanfalseRealçar a linha sob o ponteiro.
densebooleanfalseEspaçamento de célula mais apertado.