Table
Una tabla para consulta exacta: números alineados a la derecha con dígitos tabulares y un título con periodo y fuente.
| Store | Orders | Revenue (Q) | Change |
|---|---|---|---|
| Zona 10 | 1,284 | 48,210.00 | +12.4% |
| Cayalá | 962 | 37,905.50 | +4.1% |
| Antigua | 418 | 15,320.00 | −3.8% |
| Total | 2,664 | 101,435.50 | +6.3% |
Instalación
$ pnpm dlx shadcn@latest add @ssntl/tableUso
import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
<Table>
<TableCaption title="Ventas por tienda">Octubre 2026 · Fuente: POS</TableCaption>
<TableHeader>
<TableRow><TableHead>Tienda</TableHead><TableHead numeric>Ingresos</TableHead></TableRow>
</TableHeader>
<TableBody>
<TableRow><TableHead scope="row">Zona 10</TableHead><TableCell numeric>48,210.00</TableCell></TableRow>
</TableBody>
</Table>- Marca las columnas numéricas con numeric en el encabezado y en cada celda: se alinean a la derecha.
- Dígitos tabulares, la misma precisión en toda la columna y un signo menos real (−).
- Las etiquetas de fila son th scope="row"; el título da el nombre, luego periodo y fuente.
- keyRow tiñe la fila que el lector debe notar, solo cuando los datos lo justifican.
Código
import * as React from "react"
import { cn } from "@/lib/utils"
// Essential Design `es-table`: for exact lookup. Numbers align right in the
// header and every cell (`numeric`), with tabular figures only there (years
// and labels keep their normal numerals) and the same precision down a column. Text aligns left. One `is-key` row at most.
function Table({ className, ...props }: React.ComponentProps<"table">) {
return (
<div data-slot="table-wrap" className="min-w-0 overflow-x-auto">
<table
data-slot="table"
className={cn(
"w-full border-collapse text-label font-normal",
className
)}
{...props}
/>
</div>
)
}
/** A bold title, then period and source in muted text. */
function TableCaption({
title,
className,
children,
...props
}: React.ComponentProps<"caption"> & { title: React.ReactNode }) {
return (
<caption
data-slot="table-caption"
className={cn(
"pb-3 text-start text-label font-normal text-muted-foreground",
className
)}
{...props}
>
<b className="block text-body font-medium text-foreground">{title}</b>
{children}
</caption>
)
}
function TableHeader(props: React.ComponentProps<"thead">) {
return <thead data-slot="table-header" {...props} />
}
function TableBody(props: React.ComponentProps<"tbody">) {
return <tbody data-slot="table-body" {...props} />
}
function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
return (
<tfoot
data-slot="table-footer"
className={cn(
"font-medium [&_td]:border-b-0 [&_th]:border-b-0",
className
)}
{...props}
/>
)
}
function TableRow({
keyRow = false,
className,
...props
}: React.ComponentProps<"tr"> & {
/** Tints the one row the reader should notice, only when the data supports it. */
keyRow?: boolean
}) {
return (
<tr
data-slot="table-row"
data-key={keyRow || undefined}
className={cn("data-key:*:bg-muted", className)}
{...props}
/>
)
}
const cell = (numeric?: boolean) =>
cn(
"border-b border-border px-4 py-3 align-baseline first:pl-0 last:pr-0",
numeric ? "text-end tabular-nums" : "text-start"
)
function TableHead({
numeric,
className,
scope = "col",
...props
}: React.ComponentProps<"th"> & { numeric?: boolean }) {
return (
<th
data-slot="table-head"
scope={scope}
className={cn(
cell(numeric),
scope === "col"
? "border-input align-bottom text-caption font-medium text-muted-foreground"
: "font-medium whitespace-nowrap",
className
)}
{...props}
/>
)
}
function TableCell({
numeric,
className,
...props
}: React.ComponentProps<"td"> & { numeric?: boolean }) {
return (
<td
data-slot="table-cell"
className={cn(cell(numeric), className)}
{...props}
/>
)
}
export {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
}