π Anatomia de uma Data Table
Estrutura completa de tabelas profissionais
Data Tables sao componentes complexos para exibir dados tabulares com funcionalidades como ordenacao, filtragem, selecao e acoes. Diferem de tabelas HTML simples por serem interativas e otimizadas para grandes volumes.
Tabelas sao o coracao de dashboards administrativos. Lista de clientes, pedidos, transacoes - tudo vira tabela. Uma tabela mal projetada torna o sistema inutilizavel; bem projetada, e extremamente poderosa.
π Estrutura de uma Data Table
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β Selecionar todos [π Buscar...] [Filtros] [Exportar]β β Toolbar βββββββ¬βββββββββββββββββ¬βββββββββββββ¬βββββββββββ¬βββββββββββββββ€ β β β Nome ββ β Email β Status β Acoes β β Header βββββββΌβββββββββββββββββΌβββββββββββββΌβββββββββββΌβββββββββββββββ€ β β β Ana Silva β ana@... β β Ativo β [βοΈ] [ποΈ] β β Row β β β Bruno Lima β bruno@... β β Inativoβ [βοΈ] [ποΈ] β β β β Carla Dias β carla@... β β Ativo β [βοΈ] [ποΈ] β βββββββ΄βββββββββββββββββ΄βββββββββββββ΄βββββββββββ΄βββββββββββββββ€ β Mostrando 1-10 de 156 [β] [1] [2] [3] ... [βΆ] β β Footer βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π§© Componentes da Data Table
Busca global, filtros avancados, acoes em lote, exportacao.
Titulos ordenaveis, checkbox global, resize de colunas.
Dados, selecao individual, hover states, linhas expandiveis.
Paginacao, contador de resultados, itens por pagina.
ποΈ Exemplo: Mini Data Table
| Nome β | Status | ||
|---|---|---|---|
| Ana Silva | ana@exemplo.com | Ativo | |
| Bruno Lima | bruno@exemplo.com | Inativo |
π‘ Dica Pratica
Comece simples: Adicione funcionalidades incrementalmente. Uma tabela basica bem estilizada e melhor que uma super complexa cheia de bugs. Comece com ordenacao, depois adicione paginacao, depois filtros.
π Ordenacao (Sorting)
Reorganizar dados por qualquer coluna
Ordenacao permite reorganizar dados por qualquer coluna em ordem crescente ou decrescente. Usuarios esperam clicar no cabecalho para ordenar. Suportar ordenacao multipla (shift+click) e um diferencial.
Ordenacao e a funcionalidade mais usada em tabelas. "Quem sao os maiores clientes?", "Quais pedidos sao mais recentes?" - tudo requer ordenacao. Sem ela, tabelas sao estaticas e frustrantes.
π Estados de Ordenacao
Estado inicial, clicavel
Menor para maior
Maior para menor
π» Codigo: Logica de Ordenacao
// Funcao de ordenacao generica
function sortTable(data, column, direction = 'asc') {
return [...data].sort((a, b) => {
let valA = a[column];
let valB = b[column];
// Normalizar strings para comparacao
if (typeof valA === 'string') {
valA = valA.toLowerCase();
valB = valB.toLowerCase();
}
// Comparacao
if (valA < valB) return direction === 'asc' ? -1 : 1;
if (valA > valB) return direction === 'asc' ? 1 : -1;
return 0;
});
}
// Uso
const sortedData = sortTable(users, 'name', 'asc');
// Header clicavel (HTML)
<th class="cursor-pointer hover:bg-dark-700 select-none px-4 py-3"
onclick="handleSort('name')">
<span class="flex items-center">
Nome
<span class="ml-2 text-neutral-500">
{sortColumn === 'name' ? (sortDir === 'asc' ? 'β' : 'β') : 'β'}
</span>
</span>
</th>
β Fazer vs β Evitar
- β’ Indicar visualmente coluna ordenada
- β’ Ciclo: neutro β asc β desc β neutro
- β’ Manter ordenacao ao paginar
- β’ Ordenar no backend se muitos dados
- β’ Ordenar coluna sem feedback visual
- β’ Ordenar 10k+ registros no frontend
- β’ Ignorar tipos (numero vs string)
- β’ Perder ordenacao ao mudar de pagina
π Paginacao
Dividir dados em paginas gerenciaveis
Paginacao divide grandes conjuntos de dados em paginas menores. Tipicamente 10, 25, 50 ou 100 itens por pagina. Essencial para performance e usabilidade quando ha centenas ou milhares de registros.
Tabelas com 1000+ linhas sem paginacao travam o navegador e sao impossiveis de navegar. Paginacao melhora performance, facilita navegacao e permite o backend enviar dados em chunks.
π Tipos de Paginacao
Botao "Carregar mais" no final da lista. Bom para feeds infinitos.
Carrega automaticamente ao scrollar. Use com cuidado - pode ser confuso.
π» Codigo: Componente de Paginacao
<!-- Paginacao completa -->
<div class="flex items-center justify-between px-4 py-3 border-t border-dark-600">
<!-- Info de resultados -->
<p class="text-sm text-neutral-400">
Mostrando <span class="font-medium text-white">1</span> a
<span class="font-medium text-white">10</span> de
<span class="font-medium text-white">156</span> resultados
</p>
<!-- Navegacao -->
<div class="flex items-center space-x-1">
<button class="px-3 py-1.5 rounded bg-dark-700 hover:bg-dark-600
disabled:opacity-50 disabled:cursor-not-allowed"
disabled>β Anterior</button>
<button class="px-3 py-1.5 rounded bg-blue-600 text-white">1</button>
<button class="px-3 py-1.5 rounded bg-dark-700 hover:bg-dark-600">2</button>
<button class="px-3 py-1.5 rounded bg-dark-700 hover:bg-dark-600">3</button>
<span class="px-2 text-neutral-500">...</span>
<button class="px-3 py-1.5 rounded bg-dark-700 hover:bg-dark-600">16</button>
<button class="px-3 py-1.5 rounded bg-dark-700 hover:bg-dark-600">
Proximo βΆ
</button>
</div>
</div>
// Calculo de paginacao (JavaScript)
const itemsPerPage = 10;
const currentPage = 1;
const totalItems = 156;
const totalPages = Math.ceil(totalItems / itemsPerPage); // 16
const startIndex = (currentPage - 1) * itemsPerPage; // 0
const endIndex = startIndex + itemsPerPage; // 10
const pageData = allData.slice(startIndex, endIndex);
π‘ Dica Pratica
Permita configurar itens por pagina: Adicione um seletor (10, 25, 50, 100) para usuarios que preferem ver mais ou menos dados de uma vez. Power users geralmente preferem 50-100.
β‘ Virtualizacao de Tabelas
Performance com milhares de linhas
Virtualizacao renderiza apenas as linhas visiveis na tela, mesmo com milhares de registros. Conforme o usuario scrolla, linhas sao recicladas. Permite scroll "infinito" sem paginacao tradicional.
Para datasets enormes (10k+ linhas), paginacao ainda pode ser lenta. Virtualizacao mantem 60fps mesmo com 100k linhas. Bibliotecas como react-window e TanStack Virtual facilitam a implementacao.
π Como a Virtualizacao Funciona
Dados totais: 10.000 linhas Viewport visivel: ~20 linhas ββββββββββββββββββββββββββββββββββββββββ β Espaco vazio (padding-top) β β Altura simulada ββββββββββββββββββββββββββββββββββββββββ€ β Linha 245 ββββββββββββββββββββββββ β β Linha 246 ββββββββββββββββββββββββ β β Apenas linhas β Linha 247 ββββββββββββββββββββββββ β visiveis sao β Linha 248 ββββββββββββββββββββββββ β renderizadas β Linha 249 ββββββββββββββββββββββββ β no DOM β Linha 250 ββββββββββββββββββββββββ β ββββββββββββββββββββββββββββββββββββββββ€ β Espaco vazio (padding-bottom) β β Altura simulada ββββββββββββββββββββββββββββββββββββββββ Processo ao scrollar: 1. Detecta posicao do scroll 2. Calcula quais linhas estao visiveis 3. Renderiza apenas essas + buffer 4. Recicla elementos DOM existentes 5. Ajusta padding para manter scrollbar correta
π¦ Bibliotecas de Virtualizacao
Leve (~6KB), API simples. Recomendado para React.
npm install react-window
Framework-agnostic. React, Vue, Solid, Svelte.
npm install @tanstack/virtual-core
Especifico para Vue.js. Bem documentado.
npm install vue-virtual-scroller
Enterprise-grade. Virtualizacao built-in.
npm install ag-grid-community
β οΈ Quando Usar Virtualizacao
- β’ 1000+ linhas de dados
- β’ Scroll infinito e necessario
- β’ Paginacao nao e desejada pelo UX
- β’ Menos de 500 linhas
- β’ Paginacao resolve o problema
- β’ Adiciona complexidade desnecessaria
βοΈ Selecao e Acoes em Lote
Operar em multiplos registros
Selecao em lote permite selecionar multiplas linhas para executar acoes: deletar varios, exportar selecionados, alterar status em massa. Checkboxes nas linhas + checkbox "selecionar todos" no header.
Usuarios administrativos frequentemente precisam agir em multiplos registros. Sem selecao em lote, teriam que repetir a mesma acao dezenas de vezes. Produtividade aumenta exponencialmente.
π Estados do Checkbox Principal
Checkbox vazio
Checkbox indeterminado
Checkbox marcado
π» Codigo: Logica de Selecao
// Estado de selecao (usando Set para performance)
const [selectedIds, setSelectedIds] = useState(new Set());
// Toggle selecao individual
function toggleSelect(id) {
const newSet = new Set(selectedIds);
if (newSet.has(id)) {
newSet.delete(id);
} else {
newSet.add(id);
}
setSelectedIds(newSet);
}
// Toggle selecionar todos
function toggleSelectAll() {
if (selectedIds.size === data.length) {
setSelectedIds(new Set()); // deseleciona todos
} else {
setSelectedIds(new Set(data.map(item => item.id))); // seleciona todos
}
}
// Barra de acoes em lote (aparece quando ha selecao)
{selectedIds.size > 0 && (
<div class="bg-blue-900/50 border-b border-blue-500/30 px-4 py-3
flex items-center justify-between">
<span class="text-blue-300">
{selectedIds.size} item(s) selecionado(s)
</span>
<div class="flex space-x-3">
<button class="text-red-400 hover:text-red-300">
ποΈ Excluir
</button>
<button class="text-blue-400 hover:text-blue-300">
π€ Exportar
</button>
</div>
</div>
)}
π‘ Dica Pratica
Confirmacao para acoes destrutivas: Sempre peca confirmacao antes de deletar multiplos registros. Um modal simples "Voce esta prestes a excluir 15 registros. Esta acao nao pode ser desfeita." evita desastres.
π± Tabelas Responsivas
Adaptar para todas as telas
Em telas menores, nem todas as colunas cabem. Estrategias incluem: scroll horizontal, esconder colunas menos importantes, ou transformar em cards.
Dashboards sao acessados em tablets e celulares. Uma tabela de 10 colunas em mobile e inutilizavel. Definir estrategia responsiva e essencial para usabilidade multiplataforma.
π Estrategias Responsivas
Use classes Tailwind para mostrar/ocultar colunas.
class="hidden md:table-cell"
Container com overflow-x-auto.
<div class="overflow-x-auto"><table>...</table></div>
Tabela em desktop, cards em mobile.
class="hidden sm:block" / class="sm:hidden"
π» Codigo: Tabela Responsiva
<!-- Estrategia 1: Esconder colunas -->
<table class="w-full">
<thead>
<tr>
<th>Nome</th> <!-- sempre visivel -->
<th class="hidden sm:table-cell">Email</th> <!-- sm+ -->
<th class="hidden md:table-cell">Telefone</th><!-- md+ -->
<th class="hidden lg:table-cell">Empresa</th> <!-- lg+ -->
<th>Acoes</th> <!-- sempre visivel -->
</tr>
</thead>
<tbody>
<tr>
<td>Ana Silva</td>
<td class="hidden sm:table-cell">ana@email.com</td>
<td class="hidden md:table-cell">(11) 99999</td>
<td class="hidden lg:table-cell">Acme Inc</td>
<td>[Edit]</td>
</tr>
</tbody>
</table>
<!-- Estrategia 3: Card em mobile -->
<div class="hidden sm:block">
<table>...tabela completa...</table>
</div>
<div class="sm:hidden space-y-4">
{data.map(item => (
<div class="bg-dark-800 rounded-lg p-4 border border-dark-600">
<div class="font-bold">{item.name}</div>
<div class="text-sm text-neutral-400">{item.email}</div>
<div class="mt-2">[Acoes]</div>
</div>
))}
</div>