From 4df3613df794eba594ccf4c0b3a3353bb64639e2 Mon Sep 17 00:00:00 2001 From: miloschwartz Date: Tue, 21 Apr 2026 20:40:56 -0700 Subject: [PATCH] add table empty state --- src/components/ui/controlled-data-table.tsx | 107 ++++++++++--------- src/components/ui/data-table-empty-state.tsx | 46 ++++++++ src/components/ui/data-table.tsx | 99 +++++++++-------- 3 files changed, 152 insertions(+), 100 deletions(-) create mode 100644 src/components/ui/data-table-empty-state.tsx diff --git a/src/components/ui/controlled-data-table.tsx b/src/components/ui/controlled-data-table.tsx index 7217006e8..116ce644a 100644 --- a/src/components/ui/controlled-data-table.tsx +++ b/src/components/ui/controlled-data-table.tsx @@ -17,6 +17,7 @@ import { TableHeader, TableRow } from "@/components/ui/table"; +import { DataTableEmptyState } from "@/components/ui/data-table-empty-state"; import { DataTablePagination } from "@app/components/DataTablePagination"; import type { DataTableAddAction } from "@app/components/ui/data-table"; import { Button } from "@app/components/ui/button"; @@ -249,6 +250,38 @@ export function ControlledDataTable({ return ""; }; + const tableRows = table.getRowModel().rows; + const hasRows = tableRows.length > 0; + const hasAddAction = Boolean( + addButtonText && ((addActions && addActions.length > 0) || onAdd) + ); + const showAddActionInEmptyState = !hasRows && hasAddAction; + const addAction = addActions && addActions.length > 0 && addButtonText ? ( + + + + + + {addActions.map((action, i) => ( + action.onSelect()}> + {action.label} + + ))} + + + ) : onAdd && addButtonText ? ( + + ) : null; + return (
@@ -367,51 +400,15 @@ export function ControlledDataTable({
)} - {addActions && - addActions.length > 0 && - addButtonText ? ( -
- - - - - - {addActions.map((action, i) => ( - - action.onSelect() - } - > - {action.label} - - ))} - - -
- ) : ( - onAdd && - addButtonText && ( -
- -
- ) + {addAction && ( + <> +
{addAction}
+ {!showAddActionInEmptyState && ( +
+ {addAction} +
+ )} + )} @@ -606,14 +603,18 @@ export function ControlledDataTable({ )) ) : ( - - - No results found. - - + + {addAction} + + ) + : undefined + } + /> )} diff --git a/src/components/ui/data-table-empty-state.tsx b/src/components/ui/data-table-empty-state.tsx new file mode 100644 index 000000000..793c360f4 --- /dev/null +++ b/src/components/ui/data-table-empty-state.tsx @@ -0,0 +1,46 @@ +"use client"; + +import { TableCell, TableRow } from "@/components/ui/table"; +import { useTranslations } from "next-intl"; +import { type ReactNode } from "react"; + +const PLACEHOLDER_ROW_COUNT = 5; + +type DataTableEmptyStateProps = { + colSpan: number; + action?: ReactNode; +}; + +export function DataTableEmptyState({ + colSpan, + action +}: DataTableEmptyStateProps) { + const t = useTranslations(); + return ( + + +
+
+ {Array.from({ length: PLACEHOLDER_ROW_COUNT }).map( + (_, i) => ( +
+ ) + )} +
+
+

+ {t("noResults")} +

+ {action} +
+
+ + + ); +} diff --git a/src/components/ui/data-table.tsx b/src/components/ui/data-table.tsx index 2c0e5e48c..82aafe1f4 100644 --- a/src/components/ui/data-table.tsx +++ b/src/components/ui/data-table.tsx @@ -29,6 +29,7 @@ import { TableHeader, TableRow } from "@/components/ui/table"; +import { DataTableEmptyState } from "@/components/ui/data-table-empty-state"; import { Button } from "@app/components/ui/button"; import { useEffect, useMemo, useRef, useState } from "react"; import { Input } from "@app/components/ui/input"; @@ -515,6 +516,36 @@ export function DataTable({ return ""; }; + const tableRows = table.getRowModel().rows; + const hasRows = tableRows.length > 0; + const hasAddAction = Boolean( + addButtonText && ((addActions && addActions.length > 0) || onAdd) + ); + const showAddActionInEmptyState = !hasRows && hasAddAction; + const addAction = addActions && addActions.length > 0 && addButtonText ? ( + + + + + + {addActions.map((action, i) => ( + action.onSelect()}> + {action.label} + + ))} + + + ) : onAdd && addButtonText ? ( + + ) : null; + return (
@@ -651,45 +682,15 @@ export function DataTable({
)} - {addActions && addActions.length > 0 && addButtonText ? ( -
- - - - - - {addActions.map((action, i) => ( - - action.onSelect() - } - > - {action.label} - - ))} - - -
- ) : ( - onAdd && - addButtonText && ( -
- -
- ) + {addAction && ( + <> +
{addAction}
+ {!showAddActionInEmptyState && ( +
+ {addAction} +
+ )} + )}
@@ -884,14 +885,18 @@ export function DataTable({
)) ) : ( - - - No results found. - - + + {addAction} + + ) + : undefined + } + /> )}