Vai al contenuto

Tabella

Una tabella HTML semantica per fatture, elenchi amministrativi e tabelle dei prezzi — righe con bordi, intestazioni in grassetto e un'ombra decisa in stile neobrutalista.

import {
  Table,
  TableBody,

Il componente table stilizza gli elementi nativi delle tabelle HTML — <table>, <thead>, <tbody>, <th>, <td>, <caption> — senza alcuna libreria di primitive sotto; le varianti Radix e Base condividono lo stesso file. La ricetta neobrutalista: un bordo spesso e un’ombra netta attorno all’intera tabella, celle d’intestazione nel carattere dei titoli e divisori di riga da 2px.

Quando usarlo:

  • Fatture e ordini — voci di dettaglio con una riga TableFooter per il totale.
  • Elenchi di amministrazione — utenti, chiavi API, abbonamenti, con un dropdown di azioni per riga.
  • Griglie di prezzi e confronti — matrici di funzionalità dove il significato sta nelle intestazioni di colonna.

Installazione

pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/table.json
npx shadcn@latest add https://neobrutalism.com/r/base/table.json
yarn dlx shadcn@latest add https://neobrutalism.com/r/base/table.json
bunx --bun shadcn@latest add https://neobrutalism.com/r/base/table.json

Copia e incolla il seguente codice nel tuo progetto.

components/ui/table.tsx
"use client"

import * as React from "react"

import { cn } from "@/lib/utils"

function Table({ className, ...props }: React.ComponentProps<"table">) {
  return (
    <div
      data-slot="table-container"
      className="relative w-full overflow-x-auto rounded border-2 shadow-md"
    >
      <table
        data-slot="table"
        className={cn("w-full caption-bottom text-sm", className)}
        {...props}
      />
    </div>
  )
}

function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
  return (
    <thead
      data-slot="table-header"
      className={cn("[&_tr]:border-b-2", className)}
      {...props}
    />
  )
}

function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
  return (
    <tbody
      data-slot="table-body"
      className={cn("[&_tr:last-child]:border-0", className)}
      {...props}
    />
  )
}

function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
  return (
    <tfoot
      data-slot="table-footer"
      className={cn(
        "border-t-2 bg-muted/50 font-medium [&>tr]:last:border-b-0",
        className
      )}
      {...props}
    />
  )
}

function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
  return (
    <tr
      data-slot="table-row"
      className={cn(
        "border-b-2 transition-colors hover:bg-accent has-aria-expanded:bg-accent data-[state=selected]:bg-accent",
        className
      )}
      {...props}
    />
  )
}

function TableHead({ className, ...props }: React.ComponentProps<"th">) {
  return (
    <th
      data-slot="table-head"
      className={cn(
        "h-10 bg-muted px-2 text-left align-middle font-head font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0",
        className
      )}
      {...props}
    />
  )
}

function TableCell({ className, ...props }: React.ComponentProps<"td">) {
  return (
    <td
      data-slot="table-cell"
      className={cn(
        "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0",
        className
      )}
      {...props}
    />
  )
}

function TableCaption({
  className,
  ...props
}: React.ComponentProps<"caption">) {
  return (
    <caption
      data-slot="table-caption"
      className={cn("mt-4 text-sm text-muted-foreground", className)}
      {...props}
    />
  )
}

export {
  Table,
  TableHeader,
  TableBody,
  TableFooter,
  TableHead,
  TableRow,
  TableCell,
  TableCaption,
}

Aggiorna i percorsi di importazione in base alla struttura del tuo progetto.

Utilizzo

import {
  Table,
  TableBody,
  TableCaption,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"
<Table>
  <TableCaption>A list of your recent invoices.</TableCaption>
  <TableHeader>
    <TableRow>
      <TableHead className="w-[100px]">Invoice</TableHead>
      <TableHead>Status</TableHead>
      <TableHead>Method</TableHead>
      <TableHead className="text-right">Amount</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableCell className="font-medium">INV001</TableCell>
      <TableCell>Paid</TableCell>
      <TableCell>Credit Card</TableCell>
      <TableCell className="text-right">$250.00</TableCell>
    </TableRow>
  </TableBody>
</Table>

Composizione

Usa la seguente composizione per costruire una Table:

Table
├── TableCaption
├── TableHeader
│   └── TableRow
│       ├── TableHead
│       ├── TableHead
│       ├── TableHead
│       └── TableHead
├── TableBody
│   ├── TableRow
│   │   ├── TableCell
│   │   ├── TableCell
│   │   ├── TableCell
│   │   └── TableCell
│   └── TableRow
│       ├── TableCell
│       ├── TableCell
│       ├── TableCell
│       └── TableCell
└── TableFooter

Esempi

Usa il componente <TableFooter /> per aggiungere un footer alla tabella.

import {
  Table,
  TableBody,

Azioni

Una tabella che mostra le azioni per ogni riga tramite un componente <DropdownMenu />.

import { MoreHorizontalIcon } from "lucide-react"

import { Button } from "@/components/ui/button"

Data Table

Puoi usare il componente <Table /> per costruire tabelle di dati più complesse. Combinalo con @tanstack/react-table per creare tabelle con ordinamento, filtri e paginazione.

Consulta la documentazione di Data Table per maggiori informazioni.

Puoi anche vedere un esempio di tabella di dati nella demo Tasks.

RTL

Per abilitare il supporto RTL in Neobrutalism, consulta la guida alla configurazione RTL.

"use client"

import * as React from "react"

Accessibilità

Rendere gli elementi nativi delle tabelle dà agli screen reader l’annuncio della tabella, la navigazione per righe e colonne e l’associazione delle intestazioni senza alcun cablaggio ARIA. Dai un nome a ogni tabella con TableCaption e riserva TableHead alle vere celle d’intestazione. Il contenitore di scorrimento non è focalizzabile, quindi chi usa solo la tastiera non può far scorrere una tabella che deborda — se le tabelle larghe sono probabili, aggiungi tabIndex={0}, role="region" e un aria-label al div contenitore nella tua copia del componente.