DataTable

DataTable adiciona comportamento operacional a um conjunto de registros. Escolha-o quando as pessoas precisarem ordenar, selecionar ou agir sobre linhas; escolha Table quando os registros só precisarem de uma apresentação tabular simples e comparável.

Exemplos

Registros operacionais

Start with stable column keys and row id values. Put a named native action in its own cell; hover remains an optional scanning affordance.

Projects
ProjectOwnerStatusActions
AtlasMaya ChenHealthy
OrbitJon BellAt risk
NovaPriya ShahPlanning

Choose a project action to view its details.

Ordenação e seleção de linhas

Marque como sortable apenas os campos com uma ordem útil e forneça labels.selectRow como função quando cada checkbox precisar anunciar a pessoa ou o registro que seleciona.

Team members
Maya ChenDesign4
Jon BellEngineering12
Priya ShahOperations7

Linhas em carregamento

Passe um número para loading quando o resultado esperado tiver uma densidade conhecida. Isso mantém a forma da tabela enquanto os registros carregam, em vez de trocar a região de dados por um spinner.

Projects
ProjectOwnerUpdated
Loading data…

Quando usar

Use DataTable para conjuntos operacionais de registros que as pessoas precisam ordenar, selecionar, percorrer em uma área fixa ou abrir a partir de uma linha.

Prefira outro componente quando:

  • Os registros só precisam de campos alinhados para comparação — use Table, a tabela estática mais simples.
  • Os registros são arquivos que alguém precisa navegar e manipular — use FileManager.
  • Não há registros para mostrar após o carregamento — use EmptyState para uma ausência de página inteira, ou o conteúdo empty de DataTable quando a tabela ainda for um contexto útil.

Acessibilidade

  • DataTable renderiza uma <table> real, com cabeçalhos e células. Um cabeçalho ordenável é um botão, e o cabeçalho ativo informa aria-sort como crescente ou decrescente.

  • Com selectable, ela renderiza checkboxes nativos para cada linha e um checkbox de selecionar todos. O checkbox geral fica indeterminado quando apenas parte do conjunto está selecionada.

  • labels.selectRow usa por padrão o nome repetido em inglês "Select row". Passe uma string ou uma função como (row) => 'Select ' + row.name para dar a cada checkbox um nome acessível traduzido e distinguível.

  • O id da linha é usado como chave React e para seleção. Se uma linha não tiver id string ou numérico, seu fallback vem da posição original de entrada, então a seleção continua nessa linha depois da ordenação.

  • DataTable owns table layout, sorting, and selection. A command belongs to the React consumer in a cell: use a native button for an operation and a native link for navigation. Plain cells and rows are not commands.

  • Set hover to true only when a visual scanning affordance is useful. It is not implied by a consumer action.

  • Dê a cada tabela um caption descritivo (use captionHidden quando ele deve aparecer apenas para tecnologias assistivas). aria-label e aria-labelledby são encaminhados à tabela.

  • Marque a coluna de identificação com rowHeader: true; as células do corpo serão <th scope="row">. Os cabeçalhos de coluna usam scope="col".

  • A área de rolagem é uma região focável e nomeada. O nome vem do caption, ou pode ser definido com scrollLabel. Durante o carregamento, a tabela expõe aria-busy e labels.loading fornece um anúncio oculto.

React cell actions

Move each former row command into an explicit action cell during manual migration. The old onRowClick contract is removed under the project's pre-1.0 compatibility exception for unsafe contracts; the earliest correction is 0.6.0 before stable release, or stable 1.0.0. Keep the action's stable domain identity in the consumer, and keep selection and sorting callbacks separate. Styles and the static Alpine contract are unchanged.

tsx
import { useState } from 'react';
import { Badge, Button, DataTable, type DataTableColumn } from '@lyra-ds/react';

const columns: DataTableColumn[] = [
  { key: 'project', label: 'Project', rowHeader: true },
  { key: 'owner', label: 'Owner' },
  { key: 'status', label: 'Status' },
  { key: 'actions', label: 'Actions' },
];

const projects = [
  {
    id: 'atlas',
    project: 'Atlas',
    owner: 'Maya Chen',
    status: <Badge tone="success">Healthy</Badge>,
  },
  {
    id: 'orbit',
    project: 'Orbit',
    owner: 'Jon Bell',
    status: <Badge tone="warning">At risk</Badge>,
  },
  {
    id: 'nova',
    project: 'Nova',
    owner: 'Priya Shah',
    status: <Badge tone="neutral">Planning</Badge>,
  },
];

export function ProjectTable() {
  const [openedProject, setOpenedProject] = useState<string | null>(null);
  const rows = projects.map((project) => ({
    ...project,
    actions: (
      <Button
        type="button"
        size="sm"
        variant="secondary"
        onClick={() => setOpenedProject(project.id)}
        tabIndex={0}
      >
        Open {project.project}
      </Button>
    ),
  }));
  const opened = projects.find((project) => project.id === openedProject);

  return (
    <div>
      <DataTable caption="Projetos" columns={columns} rows={rows} hover />
      <p aria-live="polite">
        {opened
          ? `Showing details for ${opened.project}. Owner: ${opened.owner}.`
          : 'Choose a project action to view its details.'}
      </p>
    </div>
  );
}

API e código

NomeTipoObrigatóriaDescrição
columnsDataTableColumn[]ObrigatóriaColumns rendered in the supplied order.
rowsRowShape[]ObrigatóriaRow records whose values may be any renderable React node. An `id` value is used for keys and selection.
captionReactNode—Table caption. Supply a meaningful name for each data set.
captionHiddenboolean—Visually hide the caption while keeping it available to assistive technology.
scrollLabelstring—Accessible name for the focusable scroll region when it differs from the table name.
sortingDataTableSorting | null—Controlled sorting state. Pass `null` for unsorted rows.
defaultSortingDataTableSorting | null—Initial sorting state when uncontrolled. Default: `null`.
onSortChange(sorting: DataTableSorting | null) => void—Called after sorting changes.
selectableboolean—Whether to render row and select-all checkboxes.
selectedArray<string | number>—Controlled selected row identifiers.
defaultSelectedArray<string | number>—Initial selected row identifiers when uncontrolled.
onSelectionChange(selected: Array<string | number>) => void—Called after the selected row identifiers change.
stickyHeaderboolean—Whether the header remains visible while the table scrolls.
maxHeightnumber | string—Maximum height for the scrollable table area.
density'comfortable' | 'compact'—Row density. Default: `"comfortable"`.
loadingboolean | number—Whether to render loading placeholders, or the number of placeholder rows.
emptyReactNode—Content shown instead of the default empty-state label.
footerReactNode—Content rendered below the scrollable table area.
hoverboolean—Whether rows highlight on hover.
labelsDataTableLabels—Labels for controls and the default empty state. Merged over the English defaults.

x-data="lyraDataTable({ … })"

OpçãoTipoObrigatóriaDescrição
sortingLyraDataTableSorting | null—Controlled sort state. Modelable with `x-modelable="sorting"`. Default: `null`.
selectedstring[]—Controlled selected served row ids. Modelable with `x-modelable="selected"`. Default: `[]`.
clientSortboolean—Reorder served rows in the browser after sorting. Default: `false`.
scrollLabelstring—Accessible name for the focusable scroll region; defaults to the table caption or label.

Com o binding Alpine, sirva um <caption> e <th scope="row"> para cada célula de identificação. Adicione x-bind="header" aos <th> de colunas ordenáveis, x-bind="rowHeader" aos <th> de linhas e x-bind="scrollRegion" a .lyra-table-scroll; use lyraDataTable({ scrollLabel: "…" }) para alterar o nome da região. Cabeçalhos de colunas não ordenáveis precisam de scope="col" no HTML servido.

Sem React, componha as classes da tabela — estado de ordenação e seleção, rótulos dos checkboxes e a transição de carregamento ficam com você:

html
<div class="lyra-table-wrap">
  <div class="lyra-table-scroll" role="region" tabindex="0" aria-label="Projetos">
    <table class="lyra-table lyra-table--hover">
      <caption>
        Projetos
      </caption>
      <thead>
        <tr>
          <th scope="col" class="lyra-table__check">
            <input class="lyra-checkbox" type="checkbox" aria-label="Selecionar todos" />
          </th>
          <th scope="col" aria-sort="ascending">
            <button class="lyra-table__sortbtn lyra-table__sortbtn--active" type="button">
              Projeto
            </button>
          </th>
          <th scope="col">Status</th>
        </tr>
      </thead>
      <tbody>
        <tr class="lyra-table__row--selected">
          <td class="lyra-table__check">
            <input class="lyra-checkbox" type="checkbox" aria-label="Selecionar Atlas" checked />
          </td>
          <th scope="row" class="lyra-table__primary">Atlas</th>
          <td>Saudável</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

<lyra:data-table> Gerado do lyra-ds/blade v0.10.0.

O comportamento vem de lyraDataTable() — instale @lyra-ds/alpine e veja a aba HTML + Alpine.

PropPadrãoObrigatóriaValores de exemplo
columns—Obrigatória—
rows—Obrigatória—
sortingnull——
selectablefalse——
selected[]——
clientSortfalse——
stickyHeaderfalse——
maxHeightnull——
density'comfortable'—compact
loadingfalse——
emptynull——
hoverfalse——
labels[]——
blade
<lyra:data-table
    :columns="[
        ['key' => 'name', 'label' => 'Project', 'sortable' => true],
        ['key' => 'owner', 'label' => 'Owner'],
        ['key' => 'issues', 'label' => 'Open issues', 'align' => 'end'],
    ]"
    :rows="[
        ['id' => '1', 'name' => 'Website redesign', 'owner' => 'Ana Ribeiro', 'issues' => 12],
        ['id' => '2', 'name' => 'Mobile app', 'owner' => 'João Martins', 'issues' => 4],
    ]"
    density="comfortable"
    hover
/>