Data Table
Tabela de contatos pronta, com busca, ordenação, seleção múltipla, badges de status e paginação.
14 contatos
| Contato | Origem | Status | Valor estimado | Recebido em | |
|---|---|---|---|---|---|
Mariana Costamariana@clinicasorriso.com.br | Google Ads | Novo | R$ 4.800,00 | 27 de set. de 2026 | |
Rafael Oliveirarafael@padariapaodeouro.com.br | Formulário do site | Em atendimento | R$ 2.500,00 | 26 de set. de 2026 | |
Juliana Martinsjuliana@studiojm.com.br | Convertido | R$ 7.200,00 | 25 de set. de 2026 | ||
Carlos Eduardo Limacarlos@limaadvocacia.adv.br | Indicação | Convertido | R$ 12.900,00 | 24 de set. de 2026 | |
Fernanda Souzafernanda@petshopamigo.com.br | Novo | R$ 3.100,00 | 24 de set. de 2026 |
Mostrando 1–5 de 14
'use client';
import { DataTable } from '@/components/data-table';
export default function DataTableDemo() {
// Sem `data`, o bloco usa os contatos de exemplo (sampleContacts).
return <DataTable aria-label="Contatos recentes" className="w-full" />;
}Instalação
npx shadcn@latest add @lenstech/data-tableUso
import { DataTable } from "@/components/data-table"<DataTable aria-label="Contatos recentes" data={contatos} pageSize={10} />Um bloco é um ponto de partida
Diferente de um componente, o Data Table é para copiar e adaptar: troque o tipo Contact, as colunas,
os status e a busca pelos dados do seu sistema. Toda a lógica (filtro, ordenação e paginação) está no próprio arquivo.
Exemplos
Com seus dados
Passe data no formato Contact e ajuste pageSize. Sem data, o bloco usa os contatos de exemplo (sampleContacts).
5 contatos
| Contato | Origem | Status | Valor estimado | Recebido em | |
|---|---|---|---|---|---|
Renata Diasrenata@floriculturaflor.com.br | Novo | R$ 2.200,00 | 28 de set. de 2026 | ||
Marcos Tavaresmarcos@tavaresodonto.com.br | Google Ads | Em atendimento | R$ 5.400,00 | 27 de set. de 2026 | |
Sofia Mendessofia@mendesarquitetura.com.br | Indicação | Convertido | R$ 9.600,00 | 26 de set. de 2026 |
Mostrando 1–3 de 5
'use client';
import { DataTable, type Contact } from '@/components/data-table';
const leadsDaSemana: Contact[] = [
{ id: 'l1', nome: 'Renata Dias', email: 'renata@floriculturaflor.com.br', origem: 'Instagram', status: 'novo', valor: 2200, data: '2026-09-28' },
{ id: 'l2', nome: 'Marcos Tavares', email: 'marcos@tavaresodonto.com.br', origem: 'Google Ads', status: 'em-atendimento', valor: 5400, data: '2026-09-27' },
{ id: 'l3', nome: 'Sofia Mendes', email: 'sofia@mendesarquitetura.com.br', origem: 'Indicação', status: 'convertido', valor: 9600, data: '2026-09-26' },
{ id: 'l4', nome: 'Paulo Henrique', email: 'paulo@phfitness.com.br', origem: 'WhatsApp', status: 'perdido', valor: 1800, data: '2026-09-25' },
{ id: 'l5', nome: 'Larissa Moura', email: 'larissa@mourabuffet.com.br', origem: 'Formulário do site', status: 'novo', valor: 3900, data: '2026-09-24' },
];
export default function DataTableCustomData() {
return <DataTable aria-label="Leads da semana" data={leadsDaSemana} pageSize={3} className="w-full" />;
}Ações em lote
onSelectionChange recebe as linhas selecionadas (objetos completos, não só os ids) — ideal para exportar ou enviar e-mails em massa.
14 contatos
| Contato | Origem | Status | Valor estimado | Recebido em | |
|---|---|---|---|---|---|
Mariana Costamariana@clinicasorriso.com.br | Google Ads | Novo | R$ 4.800,00 | 27 de set. de 2026 | |
Rafael Oliveirarafael@padariapaodeouro.com.br | Formulário do site | Em atendimento | R$ 2.500,00 | 26 de set. de 2026 | |
Juliana Martinsjuliana@studiojm.com.br | Convertido | R$ 7.200,00 | 25 de set. de 2026 | ||
Carlos Eduardo Limacarlos@limaadvocacia.adv.br | Indicação | Convertido | R$ 12.900,00 | 24 de set. de 2026 | |
Fernanda Souzafernanda@petshopamigo.com.br | Novo | R$ 3.100,00 | 24 de set. de 2026 |
Mostrando 1–5 de 14
Selecione contatos para exportar.
'use client';
import * as React from 'react';
import { Button } from '@/components/ui/button';
import { DataTable, type Contact } from '@/components/data-table';
const brl = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' });
export default function DataTableSelection() {
const [selecionados, setSelecionados] = React.useState<Contact[]>([]);
const total = selecionados.reduce((soma, c) => soma + c.valor, 0);
return (
<div className="flex w-full flex-col gap-4">
<DataTable aria-label="Contatos" onSelectionChange={setSelecionados} />
<div className="flex flex-wrap items-center justify-between gap-3 rounded-md border bg-muted/50 p-3">
<p className="text-sm">
{selecionados.length === 0 ? (
<span className="text-muted-foreground">Selecione contatos para exportar.</span>
) : (
<>
<span className="font-medium">{selecionados.length}</span> selecionado(s) · potencial de{' '}
<span className="font-mono font-medium tabular-nums">{brl.format(total)}</span>
</>
)}
</p>
<Button size="sm" isDisabled={selecionados.length === 0}>
Exportar CSV
</Button>
</div>
</div>
);
}O que vem pronto
- Busca por nome, e-mail ou origem (volta para a página 1 ao digitar).
- Ordenação por contato, status, valor e data (padrão: mais recentes primeiro).
- Seleção múltipla com contador acessível (
aria-live). - Status com badge colorido: novo, em atendimento, convertido, perdido.
- Paginação com "Mostrando 1–5 de 14" e estado vazio com orientação.
Quando usar
- Use em painéis administrativos que listam leads, clientes ou pedidos.
- Não use para tabelas simples ou estáticas — use
Tablediretamente. - Não use com milhares de linhas no navegador: mova busca, ordenação e paginação para a API.
API
DataTable
Aceita as props de uma <div> HTML, mais:
Prop
Type
Contact
Prop
Type
O arquivo também exporta StatusBadge e sampleContacts.