Data table
Eine Tabelle für echte Daten, mit Sortierung, Suche, Zeilenauswahl, fixierten Spalten, Sticky Header und Paginierung.
| Method | Country | |||||
|---|---|---|---|---|---|---|
| [email protected] | Card | United States | 2026-01-01 | $5.00 | ||
| [email protected] | PayPal | Japan | 2026-02-02 | $84.20 | ||
| [email protected] | Bank | Germany | 2026-03-03 | $163.40 | ||
| [email protected] | Apple Pay | Brazil | 2026-04-04 | $242.60 | ||
| [email protected] | Card | India | 2026-05-05 | $321.80 | ||
| [email protected] | PayPal | United States | 2026-06-06 | $401.00 | ||
| [email protected] | Bank | Japan | 2026-07-07 | $480.10 | ||
| [email protected] | Apple Pay | Germany | 2026-08-08 | $559.30 | ||
| [email protected] | Card | Brazil | 2026-09-09 | $638.50 | ||
| [email protected] | PayPal | India | 2026-01-10 | $717.70 |
pnpm dlx shadcn@latest add https://hextaui.com/r/data-table.jsonFügt die Komponente, die HextaUI-Theme-Tokens und alle HextaUI-Komponenten hinzu, von denen sie abhängt.
Füge die Theme-Tokens zu deinem globalen CSS hinzu, falls du das noch nicht getan hast.
Installiere die Abhängigkeiten.
pnpm add @base-ui/react @tabler/icons-react @tanstack/react-table class-variance-authority cnKopiere den folgenden Code und füge ihn in dein Projekt ein.
components/ui/data-table.tsx components/ui/table.tsx components/ui/button.tsx components/ui/checkbox.tsx components/ui/skeleton.tsx Passe die Importpfade an dein Projekt-Setup an.
Die Data Table ist TanStack Table v9 mit bereits verdrahteten Funktionen für Sortierung, Filterung, Paginierung, Auswahl und Spaltensichtbarkeit. Definiere Spalten einmal mit createDataTableColumns, erstelle die Tabelle mit useDataTable und setze dann die benötigten Teile zusammen.
Übergib beliebigen TanStack-State, den du selbst führen willst, etwa Sortierung oder Zeilenauswahl, mit seinem Change-Handler.
DataTableColumnHeader, DataTableSelectAll und DataTableSelectRow gehören in deine Spaltendefinitionen, als Header oder Zelle einer Spalte.
Einfache Tabelle
Die einfachen <Table />-Teile, aus denen die Data Table gebaut ist. Verwende sie allein für statische Daten, mit einer Beschriftung und einer Summe im Footer.
Lädt
Mit loading füllen Skeleton-Zeilen denselben Platz wie echte Zeilen, sodass nichts springt, wenn die Daten eintreffen. Die Tabelle ist währenddessen mit aria-busy markiert.
Empty
emptyMessage füllt den Body, wenn es keine Daten gibt oder nichts zur Suche passt.
Fixierte Kopfzeile
Gib dem Container mit containerClassName eine maximale Höhe und setze stickyHeader. Die Kopfzeile bleibt stehen und erhält eine Haarlinie, sobald die Zeilen darunter scrollen. Shift-Ziehen über die Checkboxen scrollt die Box, wenn du dich ihrem Rand näherst.
Angeheftete Spalten
Die Auswahlspalte und die erste Datenspalte sind standardmäßig angeheftet. Wähle eigene mit pinStart. Ein weicher Schatten markiert den Rand, sobald die Tabelle seitlich scrollt.
Rechts nach links
Jedes Label und jeder Zähler lässt sich mit labels und den Formatfunktionen ersetzen. Paginierungspfeile und angeheftete Spalten kehren sich mit der Richtung um.
- Klicke auf eine sortierbare Kopfzeile, um aufsteigend zu sortieren, erneut für absteigend und ein drittes Mal, um zurückzusetzen. Shift-Klick auf eine weitere Kopfzeile fügt eine sekundäre Sortierung hinzu.
- Shift-Klick auf eine Zeilen-Checkbox wählt jede Zeile zwischen ihr und der zuletzt angeklickten aus. Halte Shift und ziehe über Checkboxen, um einen Bereich in einer Bewegung auszuwählen oder zu leeren.
- Die Suche trifft jede Spalte außer der Auswahlspalte und springt zurück auf die erste Seite.
- Das Ausblenden von Spalten im Ansichtsmenü hält das Menü offen, sodass du mehrere auf einmal umschalten kannst.
| Taste | Aktion |
|---|---|
| Tab | Geht durch Suche, Ansichtsmenü, sortierbare Kopfzeilen, Zeilen-Checkboxen und Paginierung. |
| EnterSpace | Sortiert nach der fokussierten Kopfzeile. |
| Space | Schaltet die fokussierte Checkbox um. |
| Esc | Leert die Suche, wenn sie Text enthält. |
- Sortierbare Kopfzeilen tragen
aria-sort, und eine Live-Region mit polite-Priorität sagt die neue Sortierung an und kurz nach dem Tippen die Anzahl der Ergebnisse. - Die Seitenanzeige ist eine Live-Region, sodass Screenreader die neue Seite nach Druck auf weiter oder zurück hören.
- Checkboxen haben standardmäßig Labels. Überschreibe sie mit
aria-labelauf<DataTableSelectAll />und<DataTableSelectRow />.
Jeder Teil unten muss innerhalb von <DataTable /> gerendert werden, das die Tabelle mit ihnen teilt.
Nimmt die TanStack-Table-Optionen und gibt die Tabelle zurück. Seiten enthalten 10 Zeilen, sofern initialState.pagination nichts anderes sagt.
| Prop | Typ | Standard |
|---|---|---|
data | TData[] | – |
columnsErstelle sie mit createDataTableColumns. | ColumnDef[] | – |
getRowIdHält die Auswahl stabil, wenn Zeilen sich bewegen. Standardmäßig der Zeilenindex. | (row: TData) => string | – |
initialState | Partial<TableState> | { pagination: { pageIndex: 0, pageSize: 10 } } |
stateSteuere sorting, rowSelection, globalFilter, pagination oder columnVisibility. | Partial<TableState> | – |
onSortingChangeJeder steuerbare State hat einen passenden Handler, etwa onRowSelectionChange. | OnChangeFn<SortingState> | – |
enableRowSelection | boolean | (row) => boolean | true |
Gibt einen typisierten Spalten-Helper mit accessor, display und columns zurück. Setze meta: { align: "end" } an numerischen Spalten, um Kopfzeile und Zellen auszurichten.
| Prop | Typ | Standard |
|---|---|---|
tableDie von useDataTable zurückgegebene Tabelle. | DataTableInstance<TData> | – |
className | string | – |
| Attribut | Beschreibung |
|---|---|
data-slot="data-table" | Der Wrapper um alle Teile. |
data-slot="data-table-announcer" | Die visuell verborgene Live-Region. |
| Prop | Typ | Standard |
|---|---|---|
emptyMessage | ReactNode | "No results." |
loading | boolean | false |
loadingRowsAnzahl der Skeleton-Zeilen beim Laden. | number | 5 |
pinStartSpalten-IDs, die am Startrand angeheftet werden. | string[] | ["select", firstColumnId] |
stickyHeaderBraucht eine maximale Höhe am Container. | boolean | false |
containerClassNameWird auf den Scroll-Container angewendet. | string | – |
swipeSelectMit Shift über Checkboxen ziehen, um einen Bereich auszuwählen. | boolean | true |
classNameWird auf das Tabellenelement angewendet. | string | – |
| Attribut | Beschreibung |
|---|---|
data-slot="table-container" | Der Scroll-Container. |
data-scrolled-start | Vorhanden am Container, wenn er vom Startrand weggescrollt ist. |
data-scrolled-end | Vorhanden, solange es zum Endrand hin noch etwas zu scrollen gibt. |
data-scrolled-top | Vorhanden, sobald die Zeilen vertikal scrollen. |
data-swipe-selecting | Vorhanden am Container während eines Shift-Ziehens. |
data-state="selected" | Vorhanden an ausgewählten Zeilen. |
data-row-id | Die Zeilen-ID aus getRowId. |
data-slot="data-table-loading-row" | Jede Skeleton-Zeile. |
data-slot="data-table-empty" | Die leere Zeile. |
Eine umbrechende Zeile für die Suche, das Ansichtsmenü und deine eigenen Filter. Akzeptiert jede div-Prop und trägt data-table-toolbar als ihr data-slot.
| Prop | Typ | Standard |
|---|---|---|
placeholder | string | "Search…" |
aria-label | string | "Search table" |
clearLabelZugänglicher Name des Löschen-Buttons. | string | "Clear search" |
| Attribut | Beschreibung |
|---|---|
data-slot="data-table-search" | Der Wrapper des Suchfelds. |
| Prop | Typ | Standard |
|---|---|---|
label | string | "View" |
groupLabel | string | "Toggle columns" |
getLabelStandardmäßig der String-Header der Spalte oder ihre ID mit Anfangsbuchstaben in Großschreibung. | (column) => string | – |
Listet jede Spalte auf, die sich ausblenden lässt. Setze enableHiding: false an einer Spalte, um sie auszulassen.
| Attribut | Beschreibung |
|---|---|
data-slot="data-table-view-options" | Das Menü-Popup. |
| Prop | Typ | Standard |
|---|---|---|
column | Column | – |
title | string | – |
Rendert einen Sortier-Button für sortierbare Spalten und einfachen Text für die übrigen.
| Attribut | Beschreibung |
|---|---|
data-slot="data-table-column-header" | Der Header-Wrapper. |
data-sorted | Vorhanden am Sortier-Button, solange die Spalte sortiert ist. |
aria-sort | An der Kopfzelle: aufsteigend, absteigend oder keine. |
| Prop | Typ | Standard |
|---|---|---|
table | Table | – |
aria-label | string | "Select all rows on this page" |
Wählt die Zeilen der aktuellen Seite aus und zeigt einen unbestimmten Zustand, wenn nur einige ausgewählt sind.
| Prop | Typ | Standard |
|---|---|---|
row | Row | – |
aria-label | string | "Select row" |
| Prop | Typ | Standard |
|---|---|---|
pageSizes | number[] | [10, 20, 50, 100] |
showSelectionDie Anzahl der ausgewählten statt der Zeilenanzahl anzeigen. | boolean | true |
labelsrowsPerPage, firstPage, previousPage, nextPage und lastPage. | Partial<DataTablePaginationLabels> | – |
formatSelection | (selected: number, total: number) => ReactNode | "2 of 42 rows selected" |
formatRows | (total: number) => ReactNode | "42 rows" |
formatPage | (page: number, pageCount: number) => ReactNode | "Page 1 of 5" |
| Attribut | Beschreibung |
|---|---|
data-slot="data-table-pagination" | Die Paginierungsleiste. |
Gibt die Tabelle des nächstgelegenen <DataTable /> zurück. Verwende es, um eigene Toolbar-Bedienelemente zu bauen, etwa einen Statusfilter.
| Prop | Typ | Standard |
|---|---|---|
stickyHeaderHeftet die Kopfzeile in einem scrollenden Container an. | boolean | false |
containerClassNameWird auf den Scroll-Container angewendet. | string | – |
containerRef | Ref<HTMLDivElement> | – |
| Attribut | Beschreibung |
|---|---|
data-slot="table" | Das Tabellenelement. |
data-sticky-header | Vorhanden am Container, wenn stickyHeader aktiv ist. |
--table-bg | Hintergrund von Zeilen und angehefteten Zellen. Folgt der Karte oder dem Popover, in dem sie sitzt. |
| Prop | Typ | Standard |
|---|---|---|
alignAm Ende ausgerichtete Zellen verwenden ebenfalls tabellarische Ziffern. | "start" | "center" | "end" | "start" |
pinnedHält die Zelle an Ort und Stelle, während die Tabelle seitlich scrollt. Versatz mit --pin-offset. | "start" | "end" | – |
pinnedEdgeZeichnet beim Scrollen einen weichen Schatten an der letzten angehefteten Spalte. | boolean | false |
| Attribut | Beschreibung |
|---|---|
data-align | Die aktuelle Ausrichtung. |
data-pinned | start oder end, wenn angeheftet. |
data-pinned-edge | Vorhanden an der letzten angehefteten Zelle einer Seite. |
--pin-offset | Abstand vom angehefteten Rand, wird automatisch gesetzt. |
TableHeader, TableBody, TableFooter, TableRow und TableCaption rendern die passenden Tabellenelemente und akzeptieren alle ihre Props.
- ButtonButtons in allen Varianten und Größen, mit eingebautem Lade-, Erfolgs- und Fehlerablauf, der den Spinner bei schnellen Anfragen überspringt.
- CheckboxEine Checkbox, deren Häkchen sich einzeichnet, mit unbestimmten übergeordneten Elementen, Gruppen und Labels, die ihren Hover teilen.
- SkeletonPlatzhalter, die 150 ms warten, bevor sie erscheinen, exakt die Größe des umschlossenen Inhalts annehmen und ihn einblenden, ohne etwas zu verschieben.
- TableEine responsive Tabelle mit Flächenstil, umbrechenden oder kompakten Zellen, fixierten Kopfzeilen, angehefteten Spalten und Scroll-Hinweisen.
- AvatarNutzerfotos mit Initialen als Fallback, Statusbadges und gestapelte Gruppen, die zu einer Zahl einklappen.
- BadgeStatuslabels mit farbigen Punkten, entfernbare Tags, die zugleiten, und Zähler, die zu ihrem neuen Wert rollen.