Data table
Un tableau pour de vraies données, avec tri, recherche, sélection de lignes, colonnes épinglées, en-tête fixe et pagination.
| 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.jsonAjoute le composant, les tokens de thème HextaUI et les composants HextaUI dont il dépend.
Ajoutez les tokens de thème à votre CSS global, si ce n’est pas déjà fait.
Installez les dépendances.
pnpm add @base-ui/react @tabler/icons-react @tanstack/react-table class-variance-authority cnCopiez et collez le code suivant dans votre projet.
components/ui/data-table.tsx components/ui/table.tsx components/ui/button.tsx components/ui/checkbox.tsx components/ui/skeleton.tsx Mettez à jour les chemins d’import selon la configuration de votre projet.
Le data table est TanStack Table v9 avec le tri, le filtrage, la pagination, la sélection et la visibilité des colonnes déjà branchés. Définissez les colonnes une seule fois avec createDataTableColumns, créez le tableau avec useDataTable, puis composez les parties dont vous avez besoin.
Passez n’importe quel état TanStack que vous voulez gérer, comme le tri ou la sélection de lignes, avec son gestionnaire de changement.
DataTableColumnHeader, DataTableSelectAll et DataTableSelectRow se placent dans vos définitions de colonnes, comme en-tête ou cellule d’une colonne.
Tableau simple
Les parties <Table /> simples dont le data table est construit. Utilisez-les seules pour des données statiques, avec une légende et un total en pied.
Chargement
Avec loading, des lignes squelettes occupent le même espace que les vraies lignes : rien ne saute à l’arrivée des données. Entre-temps, le tableau est marqué aria-busy.
Empty
emptyMessage remplit le corps lorsqu’il n’y a pas de données ou que rien ne correspond à la recherche.
En-tête fixe
Donnez au conteneur une hauteur maximale avec containerClassName et définissez stickyHeader. L’en-tête reste en place et gagne un filet fin dès que les lignes défilent dessous. Maj-glisser sur les cases à cocher fait défiler la zone à l’approche de son bord.
Colonnes épinglées
La colonne de sélection et la première colonne de données sont épinglées par défaut. Choisissez les vôtres avec pinStart. Une ombre douce marque le bord dès que le tableau défile horizontalement.
De droite à gauche
Chaque libellé et chaque compteur peut être remplacé avec labels et les fonctions de formatage. Les flèches de pagination et les colonnes épinglées s’inversent avec la direction.
- Cliquez sur un en-tête triable pour trier par ordre croissant, de nouveau pour l’ordre décroissant, et une troisième fois pour effacer. Maj-clic sur un autre en-tête pour ajouter un tri secondaire.
- Maj-clic sur la case à cocher d’une ligne pour sélectionner toutes les lignes entre elle et la dernière sur laquelle vous avez cliqué. Maintenez Maj et glissez sur des cases à cocher pour sélectionner ou effacer une plage d’un seul geste.
- La recherche porte sur toutes les colonnes sauf la colonne de sélection et revient à la première page.
- Masquer des colonnes depuis le menu View le garde ouvert : vous pouvez en basculer plusieurs d’un coup.
| Touche | Action |
|---|---|
| Tab | Parcourt la recherche, le menu View, les en-têtes triables, les cases à cocher des lignes et la pagination. |
| EnterSpace | Trie selon l’en-tête ayant le focus. |
| Space | Bascule la case à cocher ayant le focus. |
| Esc | Efface la recherche lorsqu’elle contient du texte. |
- Les en-têtes triables portent
aria-sort, et une région live polie annonce le nouveau tri ainsi que, peu après la saisie, le nombre de résultats. - L’indicateur de page est une région live : les lecteurs d’écran entendent donc la nouvelle page après un appui sur suivant ou précédent.
- Les cases à cocher ont des libellés par défaut. Remplacez-les avec
aria-labelsur<DataTableSelectAll />et<DataTableSelectRow />.
Chaque partie ci-dessous doit être rendue dans <DataTable />, qui partage le tableau avec elles.
Prend les options de TanStack Table et retourne le tableau. Les pages contiennent 10 lignes sauf si initialState.pagination indique autre chose.
| Prop | Type | Par défaut |
|---|---|---|
data | TData[] | – |
columnsConstruisez-les avec createDataTableColumns. | ColumnDef[] | – |
getRowIdGarde la sélection stable lorsque les lignes bougent. Par défaut, l’index de la ligne. | (row: TData) => string | – |
initialState | Partial<TableState> | { pagination: { pageIndex: 0, pageSize: 10 } } |
stateContrôlez sorting, rowSelection, globalFilter, pagination ou columnVisibility. | Partial<TableState> | – |
onSortingChangeChaque état contrôlable a un gestionnaire correspondant, comme onRowSelectionChange. | OnChangeFn<SortingState> | – |
enableRowSelection | boolean | (row) => boolean | true |
Retourne un assistant de colonnes typé avec accessor, display et columns. Définissez meta: { align: "end" } sur les colonnes numériques pour aligner l’en-tête et les cellules.
| Prop | Type | Par défaut |
|---|---|---|
tableLe tableau retourné par useDataTable. | DataTableInstance<TData> | – |
className | string | – |
| Attribut | Description |
|---|---|
data-slot="data-table" | L’enveloppe autour de chaque partie. |
data-slot="data-table-announcer" | La région live masquée visuellement. |
| Prop | Type | Par défaut |
|---|---|---|
emptyMessage | ReactNode | "No results." |
loading | boolean | false |
loadingRowsNombre de lignes squelettes pendant le chargement. | number | 5 |
pinStartIds des colonnes à épingler au bord de départ. | string[] | ["select", firstColumnId] |
stickyHeaderNécessite une hauteur maximale sur le conteneur. | boolean | false |
containerClassNameAppliqué au conteneur de défilement. | string | – |
swipeSelectMaj-glissez sur des cases à cocher pour sélectionner une plage. | boolean | true |
classNameAppliqué à l’élément table. | string | – |
| Attribut | Description |
|---|---|
data-slot="table-container" | Le conteneur de défilement. |
data-scrolled-start | Présent sur le conteneur lorsqu’il a défilé loin du bord de départ. |
data-scrolled-end | Présent tant qu’il reste du contenu à faire défiler vers le bord de fin. |
data-scrolled-top | Présent une fois que les lignes défilent verticalement. |
data-swipe-selecting | Présent sur le conteneur pendant un Maj-glissement. |
data-state="selected" | Présent sur les lignes sélectionnées. |
data-row-id | L’id de la ligne issu de getRowId. |
data-slot="data-table-loading-row" | Chaque ligne squelette. |
data-slot="data-table-empty" | La ligne vide. |
Une ligne à retour automatique pour la recherche, le menu View et vos propres filtres. Accepte toutes les props de div et porte data-table-toolbar comme data-slot.
| Prop | Type | Par défaut |
|---|---|---|
placeholder | string | "Search…" |
aria-label | string | "Search table" |
clearLabelNom accessible du bouton d’effacement. | string | "Clear search" |
| Attribut | Description |
|---|---|
data-slot="data-table-search" | L’enveloppe du champ de recherche. |
| Prop | Type | Par défaut |
|---|---|---|
label | string | "View" |
groupLabel | string | "Toggle columns" |
getLabelPar défaut, l’en-tête de type chaîne de la colonne, ou son id avec une majuscule. | (column) => string | – |
Liste toutes les colonnes qui peuvent être masquées. Définissez enableHiding: false sur une colonne pour l’exclure.
| Attribut | Description |
|---|---|
data-slot="data-table-view-options" | La popup du menu. |
| Prop | Type | Par défaut |
|---|---|---|
column | Column | – |
title | string | – |
Rend un bouton de tri pour les colonnes triables et du texte simple pour les autres.
| Attribut | Description |
|---|---|
data-slot="data-table-column-header" | L’enveloppe de l’en-tête. |
data-sorted | Présent sur le bouton de tri tant que la colonne est triée. |
aria-sort | Sur la cellule d’en-tête : croissant, décroissant ou aucun. |
| Prop | Type | Par défaut |
|---|---|---|
table | Table | – |
aria-label | string | "Select all rows on this page" |
Sélectionne les lignes de la page actuelle et affiche un état indéterminé lorsque seules certaines sont sélectionnées.
| Prop | Type | Par défaut |
|---|---|---|
row | Row | – |
aria-label | string | "Select row" |
| Prop | Type | Par défaut |
|---|---|---|
pageSizes | number[] | [10, 20, 50, 100] |
showSelectionAffiche le nombre de lignes sélectionnées au lieu du nombre de lignes. | boolean | true |
labelsrowsPerPage, firstPage, previousPage, nextPage et 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 | Description |
|---|---|
data-slot="data-table-pagination" | La barre de pagination. |
Retourne le tableau du <DataTable /> le plus proche. Utilisez-le pour construire vos propres contrôles de barre d’outils, comme un filtre de statut.
| Prop | Type | Par défaut |
|---|---|---|
stickyHeaderÉpingle la ligne d’en-tête dans un conteneur défilant. | boolean | false |
containerClassNameAppliqué au conteneur de défilement. | string | – |
containerRef | Ref<HTMLDivElement> | – |
| Attribut | Description |
|---|---|
data-slot="table" | L’élément table. |
data-sticky-header | Présent sur le conteneur lorsque stickyHeader est activé. |
--table-bg | Arrière-plan des lignes et des cellules épinglées. Suit la carte ou le popover dans lequel il se trouve. |
| Prop | Type | Par défaut |
|---|---|---|
alignLes cellules alignées à la fin utilisent aussi des chiffres tabulaires. | "start" | "center" | "end" | "start" |
pinnedGarde la cellule en place pendant le défilement horizontal du tableau. Décalage avec --pin-offset. | "start" | "end" | – |
pinnedEdgeDessine une ombre douce sur la dernière colonne épinglée pendant le défilement. | boolean | false |
| Attribut | Description |
|---|---|
data-align | L’alignement actuel. |
data-pinned | start ou end lorsqu’elle est épinglée. |
data-pinned-edge | Présent sur la dernière cellule épinglée d’un côté. |
--pin-offset | Distance au bord épinglé, définie pour vous. |
TableHeader, TableBody, TableFooter, TableRow et TableCaption rendent les éléments de tableau correspondants et acceptent toutes leurs props.
- ButtonDes boutons dans toutes les variantes et tailles, avec un flux de chargement, de succès et d’erreur intégré qui évite le spinner pour les requêtes rapides.
- CheckboxUne case à cocher dont la coche se dessine, avec des parents indéterminés, des groupes et des libellés qui partagent son survol.
- SkeletonDes placeholders qui attendent 150ms avant de s’afficher, prennent la taille exacte du contenu qu’ils enveloppent et l’affichent en fondu sans rien déplacer.
- TableUn tableau responsive avec un style de surface, des cellules à retour à la ligne ou compactes, des en-têtes fixes, des colonnes épinglées et des indications de défilement.
- AvatarDes photos d’utilisateurs avec initiales en repli, badges de statut et groupes empilés qui se réduisent en compteur.
- BadgeDes libellés de statut avec pastilles colorées, des tags amovibles qui se referment en glissant et des compteurs qui défilent vers leur nouvelle valeur.