YYayaw

Référence DataTable

Référence des props et usages du composant DataTable unifié

Référence DataTable

Composant point d'entrée unique : vous passez config + actions en props ; il compose le provider, l'UI et la logique de table en interne.

import { DataTable } from "@/components/ui/yayaw-table";

Pour un setup minimal fonctionnel, il vous faut tableType, getTableConfig et getTableActions. Voir Provider & Setup pour la vue complète et le layout Next.js (NuqsAdapter, QueryClientProvider).

Si aucun QueryClient n'est disponible depuis le contexte (et qu'aucune prop queryClient explicite n'est fournie), DataTable lève maintenant une erreur runtime explicite.

Props

Liste des props disponibles pour configurer DataTable.

tableType

Type de configuration de table. Utilisé pour résoudre config et actions (getTableConfig("products"), getTableActions("products")).

<DataTable tableType="products" />

Requis : true

tableId

Identifiant stable de l'instance de table pour l'état d'URL, le cache, la sélection, la pagination et la toolbar. Par défaut : tableType.

Utilisez-le quand une même table affiche plusieurs modèles métier mais doit garder un seul état partagé.

Type : string

formType

Type de formulaire par défaut pour create/edit. Par défaut : tableType. La config de table peut le surcharger avec form.createFormType, form.editFormType ou form.resolveEditFormType(row).

Type : string

getTableConfig

Fonction qui retourne la configuration table/colonnes pour le tableType donné. Requise pour définir colonnes, tri, visibilité et options.

Type : (tableType: string) => Config | undefined

getTableActions

Fonction qui retourne les actions (list, create, update, delete, bulk, etc.) pour le tableType. list est obligatoire pour les données server-driven.

Type : (tableType: string) => TableActions | undefined

getFormConfig

Fonction qui retourne les définitions de champs pour les dialogs create/edit et bulk edit. Optionnelle, mais nécessaire pour les formulaires intégrés.

Type : (formType: string, ctx?: FormConfigContext) => FormConfig | undefined

ctx contient { mode, tableId, tableType, formType, row, initialData, values }, ce qui permet de changer les champs selon la ligne éditée ou les valeurs courantes du formulaire.

queryClient

Instance TanStack Query explicite optionnelle. Yayaw Table n'en crée plus en interne. Dans la plupart des apps, utilisez un QueryClientProvider partagé au niveau app et omettez cette prop.

Type : QueryClient

initialData

Lignes injectées dans le premier état client de la table. Utilisez cette prop quand un Server Component a déjà chargé la première page et que vous voulez hydrater la table avec des données utiles avant le refresh client TanStack Query.

Type : Record<string, unknown>[] | Par défaut : []

initialPageCount

Nombre total de pages correspondant à initialData. Fournissez-le pour les jeux de données paginés côté serveur afin que le premier rendu garde les bons contrôles de pagination au lieu de supposer une seule page.

Type : number | Par défaut : 1 quand initialData est présent

initialRowCount

Nombre total de lignes correspondant à initialData. Fournissez-le quand le serveur connaît le total filtré complet de la première page.

Type : number | Par défaut : initialData.length

className

Classes additionnelles appliquées au wrapper racine.

Type : string | Par défaut : undefined

loadingOverlay

Surcouche de chargement personnalisée affiché pendant le chargement des données.

Type : React.ReactNode | Par défaut : spinner interne

<DataTable tableType="products" loadingOverlay={<MySpinner />} />

onRowSelectionChange

Callback déclenché quand la sélection de lignes change.

Type : (rows: Row<Record<string, unknown>>[]) => void | Par défaut : undefined

activeRowId

Marque une ligne comme active. Utile pour les tables master-detail où la table est la surface d'inventaire et un autre panneau affiche la ligne sélectionnée.

Type : string | Par défaut : undefined

getRowId

Retourne un id de ligne stable pour le surlignage actif, la sélection et les métadonnées de ligne. Si omis, la table utilise les champs id courants puis l'id React Table.

Type : (row: Record<string, unknown>) => string | Par défaut : undefined

onRowActivate

Callback déclenché quand table.rowClickMode vaut 'activate' et qu'une zone non interactive de ligne ou de carte est cliquée.

Type : (row: Record<string, unknown>, event: React.MouseEvent) => void | Par défaut : undefined

onRowClick

Callback déclenché par les interactions de lien, y compris les clics de ligne en mode row-link et les boutons lien de Gallery. Utilisez-le pour router via votre app ou suivre de l'analytics au lieu de dépendre du comportement navigateur par défaut.

Type : (url: string, row: Record<string, unknown>, event: React.MouseEvent) => void | Par défaut : undefined

onBulkEdit

Gère l'édition de masse des lignes sélectionnées.

Type : (rows: Row<Record<string, unknown>>[]) => BulkActionResult | void | Promise<BulkActionResult | void> | Par défaut : actions provider

onBulkDelete

Gère la suppression de masse des lignes sélectionnées.

Type : (rows: Row<Record<string, unknown>>[]) => BulkActionResult | BulkDeleteExecutionOutcome | void | Promise<...> | Par défaut : provider bulkDelete / delete

onBulkCopy

Gère la duplication de masse des lignes sélectionnées.

Type : (rows: Row<Record<string, unknown>>[]) => BulkActionResult | void | Promise<BulkActionResult | void> | Par défaut : copie clipboard interne

onExport

Surcharge le comportement d'export de la barre d'outils. Appelé avec toutes les lignes correspondant à l'état courant (search/filters/sort).

Type : (rows: Record<string, unknown>[]) => void \| Promise<void> | Par défaut : export CSV interne

onBulkExport

Surcharge le comportement d'export bulk. Appelé avec les lignes sélectionnées.

Type : (rows: Row<Record<string, unknown>>[]) => void \| Promise<void> | Par défaut : export CSV interne

toolbarActions

Injecte des actions personnalisées dans la barre d'outils principale. Accepte un tableau statique ou une fonction recevant le contexte courant.

Type : ToolbarAction[] | ((ctx: ToolbarActionContext) => ToolbarAction[]) | Par défaut : undefined

toolbarActionsPlacement

Contrôle l'emplacement des actions personnalisées par rapport aux actions natives.

Type : "before-create" | "between-create-export" | "after-export" | Par défaut : "between-create-export"

ToolbarAction et ToolbarActionContext

type ToolbarAction = {
  id: string;
  label: string;
  icon?: ReactNode;
  onClick: (ctx: ToolbarActionContext) => void | Promise<void>;
  disabled?: boolean | ((ctx: ToolbarActionContext) => boolean);
  loading?: boolean;
  variant?: "default" | "outline" | "secondary" | "ghost" | "destructive";
  showInIconMode?: boolean; // true par défaut
  tooltip?: string;
};

type ToolbarActionContext = {
  tableId: string;
  actionsAsIcons: boolean;
  isMobile: boolean;
  isCreateEnabled: boolean;
  isExportEnabled: boolean;
  isExporting: boolean;
  hasListAction: boolean;
  selectedRows: Row<Record<string, unknown>>[];
  selectedOriginalRows: Record<string, unknown>[];
  selectedRowIds: string[];
  selectedCount: number;
  tableActions?: TableActions;
};

Table Multi-Modèles

Une seule table peut garder un tableId commun tout en séparant la config table et la config formulaire :

<DataTable
  tableId="cms-entries"
  tableType="content-index"
  formType="content-entry"
  getTableConfig={(tableType) => ({
    ...configs[tableType],
    form: {
      createFormType: "content-entry",
      resolveEditFormType: (row) => `${row.modelId}-entry`,
    },
  })}
  getFormConfig={(formType, ctx) =>
    buildEntryForm({
      formType,
      modelId: String(ctx?.values?.modelId ?? ctx?.row?.modelId ?? ""),
    })
  }
  customBulkActions={(ctx) => [
    {
      id: "publish-selected",
      label: "Publish",
      icon: Send,
      disabled: ctx.selectedCount === 0,
      onClick: async () => publishEntries(ctx.selectedOriginalRows),
    },
    {
      id: "archive-selected",
      label: "Archive",
      icon: Archive,
      variant: "destructive",
      disabled: ctx.selectedCount === 0,
      confirm: {
        title: "Archive selected entries?",
        description: `Archive ${ctx.selectedCount} selected entries.`,
      },
      onClick: async () => archiveEntries(ctx.selectedOriginalRows),
    },
  ]}
/>

Ici cms-entries pilote URL/cache/sélection, content-index pilote les colonnes et filtres, et chaque ligne peut ouvrir son propre type de formulaire d'édition.

Données initiales server-first

Pour les pages Next.js App Router, chargez la première page dans un Server Component, puis passez les lignes et la pagination à un petit Client Component qui rend DataTable.

// app/products/page.tsx
import { listProducts } from "./actions/products";
import { ProductsTableClient } from "./products-table-client";

export default async function ProductsPage() {
  const initial = await listProducts({ limit: 10, page: 1 });

  return (
    <ProductsTableClient
      initialData={initial.data}
      initialPageCount={initial.meta.pageCount}
      initialRowCount={initial.meta.totalCount}
    />
  );
}
// app/products/products-table-client.tsx
"use client";

import { DataTable } from "@/components/ui/yayaw-table";
import { listProducts } from "./actions/products";
import { getTableConfig } from "./table-config";

export function ProductsTableClient({
  initialData,
  initialPageCount,
  initialRowCount,
}: {
  initialData: Record<string, unknown>[];
  initialPageCount: number;
  initialRowCount: number;
}) {
  return (
    <DataTable
      getTableActions={() => ({ list: listProducts })}
      getTableConfig={getTableConfig}
      initialData={initialData}
      initialPageCount={initialPageCount}
      initialRowCount={initialRowCount}
      tableType="products"
    />
  );
}

initialData est uniquement la première valeur de cache. Tri, filtres, pagination, retry et refresh continuent d'appeler votre action getTableActions().list via TanStack Query, donc l'autorisation et l'accès aux données restent dans votre couche serveur.

enableAdvancedFilters

Active l'UI de filtres avancés si disponible dans votre configuration.

Type : boolean | Par défaut : false

columnTypeMapping

Mappe vos types backend dynamiques vers les types de rendu internes.

Type : Record<string, 'text' | 'number' | 'date' | 'option' | 'multiOption'> | Par défaut : {}

Usage

<DataTable
  tableType="products"
  loadingOverlay={<MySpinner />}
  onRowSelectionChange={(rows) => console.log(rows)}
  onBulkDelete={(rows) => console.log("delete", rows.length)}
  onExport={(rows) => console.log("export all", rows.length)}
  onBulkExport={(rows) => console.log("export selected", rows.length)}
/>

Action personnalisée en mode texte :

<DataTable
  tableType="products"
  toolbarActions={[
    {
      id: "recalculate-prices",
      label: "Recalculate prices",
      onClick: async () => {
        await recalculatePrices();
      },
      variant: "secondary",
    },
  ]}
/>

Action personnalisée en mode icône avec tooltip et placement explicite :

<DataTable
  tableType="products"
  toolbarActions={(ctx) => [
    {
      id: "recalculate-prices",
      label: "Recalculate prices",
      tooltip: "Recalculate prices",
      icon: <RefreshCw className="h-4 w-4" />,
      disabled: () => !ctx.hasListAction || ctx.isExporting,
      onClick: async () => {
        await recalculatePrices();
      },
    },
  ]}
  toolbarActionsPlacement="between-create-export"
/>

Compatibilité: si toolbarActions n'est pas défini, le comportement de la toolbar reste inchangé.

Voir aussi :