1 items selected
Name | Email | Role | Status | |
|---|---|---|---|---|
John Smith | john@example.com | Admin | active | |
Sarah Johnson | sarah@example.com | Editor | active | |
Mike Wilson | mike@example.com | Viewer | inactive | |
Emily Davis | emily@example.com | Editor | pending |
A feature-rich data grid with sorting, selection, resizing, and responsive layouts.
Name | Email | Status |
|---|---|---|
Jane Cooper | jane@example.com | active |
Wade Warren | wade@example.com | pending |
Esther Howard | esther@example.com | inactive |
"use client";
import { Badge, DataTable, type Column } from '@photonix/ultimate';
interface UserRow {
id: number;
name: string;
email: string;
status: 'active' | 'pending' | 'inactive';
}
const users: UserRow[] = [
{ id: 1, name: 'Jane Cooper', email: 'jane@example.com', status: 'active' },
{ id: 2, name: 'Wade Warren', email: 'wade@example.com', status: 'pending' },
{ id: 3, name: 'Esther Howard', email: 'esther@example.com', status: 'inactive' },
];
const columns: Column<UserRow>[] = [
{ key: 'name', title: 'Name', sortable: true },
{ key: 'email', title: 'Email' },
{
key: 'status',
title: 'Status',
render: (value) => {
const status = value as UserRow['status'];
const color = status === 'active' ? 'green' : status === 'pending' ? 'orange' : 'gray';
return <Badge color={color} label={status} />;
},
},
];
export default function DataTableBasicExample() {
return <DataTable columns={columns} data={users} rowKey="id" />;
}Prop | Type | Default | Description |
|---|---|---|---|
columns | Column<T>[] | - | Array of column definitions |
data | T[] | - | Array of data rows |
rowKey | keyof T | ((row: T) => string | number) | - | Unique key accessor for each row |
selectable | boolean | false | Enable row selection |
selectedKeys | (string | number)[] | [] | Selected row keys |
onSelectionChange | ((keys: (string | number)[]) => void) | - | Callback when selection changes |
sortKey | string | null | null | Current sort column key |
sortDirection | SortDirection | null | Current sort direction |
onSortChange | ((key: string, direction: SortDirection) => void) | - | Callback when sort changes |
loading | boolean | false | Loading state |
emptyContent | React.ReactNode | - | Empty state content |
stickyHeader | boolean | false | Sticky header |
height | string | number | - | Table height (enables vertical scroll) |
striped | boolean | false | Show alternating row colors |
hoverable | boolean | true | Show row hover effect |
bordered | boolean | false | Show borders between cells |
compact | boolean | false | Compact row height (deprecated, use size="small") |
tableLayout | "auto" | "fixed" | 'fixed' | Table layout algorithm |
size | "small" | "large" | "medium" | 'medium' | Table density/size |
className | string | - | Optional class name |
style | React.CSSProperties | - | Optional style |
pagination | { current: number; pageSize: number; total: number; onChange: (page: number) => void; onPageSizeChange?: (pageSize: number) => void; pageSizeOptions?: number[]; showSizeChanger?: boolean; } | - | Pagination config |
onRowClick | ((row: T, rowIndex: number) => void) | - | Row click handler |
flush | boolean | false | Remove border and border-radius for embedding inside containers like Card |
rowActions | ((row: T, rowIndex: number) => React.ReactNode) | - | Floating row actions rendered on hover at the right edge of each row |
Prop | Type | Default | Description |
|---|---|---|---|
key | string | | Unique identifier for the column. |
title | string | | Header text. |
width | string | | CSS width value. |
sortable | boolean | | Enable sorting for this column. |
sticky | boolean | | Fix column to the left. |
align | 'left' | 'center' | 'right' | | Text alignment. |
cellVariant | string | | Preset styles (avatar, money, date, id, actions, nowrap). |
render | (val, row, index) => ReactNode | | Custom cell renderer. |
Enable individual and bulk selection with simple props.
1 items selected
Name | Email | Role | Status | |
|---|---|---|---|---|
John Smith | john@example.com | Admin | active | |
Sarah Johnson | sarah@example.com | Editor | active | |
Mike Wilson | mike@example.com | Viewer | inactive | |
Emily Davis | emily@example.com | Editor | pending |
"use client";
import { Badge, Button, DataTable, Flex, Stack, Text, type Column } from '@photonix/ultimate';
import { useState } from 'react';
interface UserRow {
id: string;
name: string;
email: string;
role: string;
status: 'active' | 'pending' | 'inactive';
}
const users: UserRow[] = [
{ id: '1', name: 'John Smith', email: 'john@example.com', role: 'Admin', status: 'active' },
{ id: '2', name: 'Sarah Johnson', email: 'sarah@example.com', role: 'Editor', status: 'active' },
{ id: '3', name: 'Mike Wilson', email: 'mike@example.com', role: 'Viewer', status: 'inactive' },
{ id: '4', name: 'Emily Davis', email: 'emily@example.com', role: 'Editor', status: 'pending' },
];
const columns: Column<UserRow>[] = [
{ key: 'name', title: 'Name', width: '250px' },
{ key: 'email', title: 'Email', width: 'auto' },
{ key: 'role', title: 'Role', width: '150px' },
{
key: 'status',
title: 'Status',
width: '120px',
render: (val) => <Badge color={val === 'active' ? 'green' : val === 'pending' ? 'orange' : 'gray'} label={String(val)} />,
},
];
export default function DataTableSelectionExample() {
const [selectedKeys, setSelectedKeys] = useState<(string | number)[]>(['1']);
return (
<Stack gap="md" w="100%">
<Flex justify="between" align="center">
<Text color="secondary" variant="body-sm">{selectedKeys.length} items selected</Text>
<Button size="small" variant="secondary" disabled={selectedKeys.length === 0} onClick={() => setSelectedKeys([])}>Clear Selection</Button>
</Flex>
<DataTable columns={columns} data={users} rowKey="id" selectable selectedKeys={selectedKeys} onSelectionChange={setSelectedKeys} />
</Stack>
);
}Professional sorting with active states and dimmed inactive icons.
Name | Role | Revenue |
|---|---|---|
Emily Davis | Editor | $15,800 |
John Smith | Admin | $12,500 |
Sarah Johnson | Editor | $8,900 |
Mike Wilson | Viewer | $3,200 |
"use client";
import { DataTable, type Column } from '@photonix/ultimate';
import { useMemo, useState } from 'react';
interface UserRow {
id: string;
name: string;
role: string;
revenue: number;
}
const users: UserRow[] = [
{ id: '1', name: 'John Smith', role: 'Admin', revenue: 12500 },
{ id: '2', name: 'Sarah Johnson', role: 'Editor', revenue: 8900 },
{ id: '3', name: 'Mike Wilson', role: 'Viewer', revenue: 3200 },
{ id: '4', name: 'Emily Davis', role: 'Editor', revenue: 15800 },
];
const columns: Column<UserRow>[] = [
{ key: 'name', title: 'Name', sortable: true },
{ key: 'role', title: 'Role', sortable: true },
{ key: 'revenue', title: 'Revenue', sortable: true, align: 'right', render: (v) => `$${Number(v).toLocaleString()}` },
];
export default function DataTableSortingExample() {
const [sortKey, setSortKey] = useState<string | null>('revenue');
const [sortDirection, setSortDirection] = useState<'asc' | 'desc' | null>('desc');
const sortedData = useMemo(() => {
if (!sortKey || !sortDirection) return users;
return [...users].sort((a, b) => {
const aVal = a[sortKey as keyof UserRow];
const bVal = b[sortKey as keyof UserRow];
if (aVal < bVal) return sortDirection === 'asc' ? -1 : 1;
if (aVal > bVal) return sortDirection === 'asc' ? 1 : -1;
return 0;
});
}, [sortKey, sortDirection]);
return <DataTable columns={columns} data={sortedData} rowKey="id" sortKey={sortKey} sortDirection={sortDirection} onSortChange={(key, dir) => { setSortKey(dir ? key : null); setSortDirection(dir); }} />;
}Integrated pagination with page size controls.
Name | Email | Role | Status |
|---|---|---|---|
John Smith | john@example.com | Admin | active |
Sarah Johnson | sarah@example.com | Editor | active |
Mike Wilson | mike@example.com | Viewer | inactive |
"use client";
import { Badge, DataTable, type Column } from '@photonix/ultimate';
import { useMemo, useState } from 'react';
interface UserRow {
id: string;
name: string;
email: string;
role: string;
status: 'active' | 'pending' | 'inactive';
}
const users: UserRow[] = [
{ id: '1', name: 'John Smith', email: 'john@example.com', role: 'Admin', status: 'active' },
{ id: '2', name: 'Sarah Johnson', email: 'sarah@example.com', role: 'Editor', status: 'active' },
{ id: '3', name: 'Mike Wilson', email: 'mike@example.com', role: 'Viewer', status: 'inactive' },
{ id: '4', name: 'Emily Davis', email: 'emily@example.com', role: 'Editor', status: 'pending' },
{ id: '5', name: 'David Brown', email: 'david@example.com', role: 'Admin', status: 'active' },
{ id: '6', name: 'Lisa Anderson', email: 'lisa@example.com', role: 'Viewer', status: 'active' },
];
const columns: Column<UserRow>[] = [
{ key: 'name', title: 'Name', width: '250px' },
{ key: 'email', title: 'Email', width: 'auto' },
{ key: 'role', title: 'Role', width: '150px' },
{
key: 'status',
title: 'Status',
width: '120px',
render: (val) => <Badge color={val === 'active' ? 'green' : val === 'pending' ? 'orange' : 'gray'} label={String(val)} />,
},
];
export default function DataTablePaginationExample() {
const [currentPage, setCurrentPage] = useState(1);
const displayData = useMemo(() => {
const pageSize = 3;
const start = (currentPage - 1) * pageSize;
return users.slice(start, start + pageSize);
}, [currentPage]);
return <DataTable columns={columns} data={displayData} rowKey="id" pagination={{ current: currentPage, pageSize: 3, total: users.length, onChange: setCurrentPage }} />;
}A smooth spinner overlay blocks interaction while fetching data.
Name | Email | Role | Status |
|---|---|---|---|
John Smith | john@example.com | Admin | active |
Sarah Johnson | sarah@example.com | Editor | active |
Mike Wilson | mike@example.com | Viewer | inactive |
"use client";
import { Badge, Button, DataTable, Stack, type Column } from '@photonix/ultimate';
import { useState } from 'react';
interface UserRow {
id: string;
name: string;
email: string;
role: string;
status: 'active' | 'pending' | 'inactive';
}
const users: UserRow[] = [
{ id: '1', name: 'John Smith', email: 'john@example.com', role: 'Admin', status: 'active' },
{ id: '2', name: 'Sarah Johnson', email: 'sarah@example.com', role: 'Editor', status: 'active' },
{ id: '3', name: 'Mike Wilson', email: 'mike@example.com', role: 'Viewer', status: 'inactive' },
];
const columns: Column<UserRow>[] = [
{ key: 'name', title: 'Name', width: '250px' },
{ key: 'email', title: 'Email', width: 'auto' },
{ key: 'role', title: 'Role', width: '150px' },
{
key: 'status',
title: 'Status',
width: '120px',
render: (val) => <Badge color={val === 'active' ? 'green' : val === 'pending' ? 'orange' : 'gray'} label={String(val)} />,
},
];
export default function DataTableLoadingExample() {
const [loading, setLoading] = useState(false);
return (
<Stack gap="md" w="100%">
<Button variant="secondary" onClick={() => { setLoading(true); setTimeout(() => setLoading(false), 2000); }}>Simulate API Call</Button>
<DataTable columns={columns} data={users} rowKey="id" loading={loading} />
</Stack>
);
}Fix columns to the left to maintain context while scrolling horizontally.
Name | Email | Phone | Role | Revenue | Status | |
|---|---|---|---|---|---|---|
John Smith | john@example.com | +1 234 567 890 | Admin | $12,500 | active | |
Sarah Johnson | sarah@example.com | +1 234 567 891 | Editor | $8,900 | active | |
Mike Wilson | mike@example.com | +1 234 567 892 | Viewer | $3,200 | inactive | |
Emily Davis | emily@example.com | +1 234 567 893 | Editor | $15,800 | pending | |
David Brown | david@example.com | +1 234 567 894 | Admin | $22,100 | active | |
Lisa Anderson | lisa@example.com | +1 234 567 895 | Viewer | $5,400 | active |
"use client";
import { DataTable, type Column } from '@photonix/ultimate';
interface UserRow {
id: string;
name: string;
email: string;
phone: string;
role: string;
revenue: number;
status: string;
}
const users: UserRow[] = [
{ id: '1', name: 'John Smith', email: 'john@example.com', phone: '+1 234 567 890', role: 'Admin', revenue: 12500, status: 'active' },
{ id: '2', name: 'Sarah Johnson', email: 'sarah@example.com', phone: '+1 234 567 891', role: 'Editor', revenue: 8900, status: 'active' },
{ id: '3', name: 'Mike Wilson', email: 'mike@example.com', phone: '+1 234 567 892', role: 'Viewer', revenue: 3200, status: 'inactive' },
{ id: '4', name: 'Emily Davis', email: 'emily@example.com', phone: '+1 234 567 893', role: 'Editor', revenue: 15800, status: 'pending' },
{ id: '5', name: 'David Brown', email: 'david@example.com', phone: '+1 234 567 894', role: 'Admin', revenue: 22100, status: 'active' },
{ id: '6', name: 'Lisa Anderson', email: 'lisa@example.com', phone: '+1 234 567 895', role: 'Viewer', revenue: 5400, status: 'active' },
];
const columns: Column<UserRow>[] = [
{ key: 'name', title: 'Name', width: '200px', sticky: true },
{ key: 'email', title: 'Email', width: '300px' },
{ key: 'phone', title: 'Phone', width: '200px' },
{ key: 'role', title: 'Role', width: '150px' },
{ key: 'revenue', title: 'Revenue', width: '150px', align: 'right', render: (val) => `$${Number(val).toLocaleString()}` },
{ key: 'status', title: 'Status', width: '150px', sticky: true },
];
export default function DataTableStickyExample() {
return (
<div style={{ maxWidth: '600px', overflow: 'hidden', border: 'var(--border-sm) solid var(--border-neutral-tertiary)', borderRadius: 'var(--radius-xs)' }}>
<DataTable columns={columns} data={users} rowKey="id" selectable flush />
</div>
);
}When the last column is an actions column, DataTable can mirror it as floating row actions while the right edge is clipped. Hover a row before scrolling horizontally to see the actions stay accessible.
Name | Email | Role | ||
|---|---|---|---|---|
John Smith | john@example.com | Admin | ||
Sarah Johnson | sarah@example.com | Editor | ||
Mike Wilson | mike@example.com | Viewer | ||
Emily Davis | emily@example.com | Editor |
"use client";
import { Box, DataTable, Flex, IconButton, type Column } from '@photonix/ultimate';
import { PenOutline, TrashOutline } from '@photonix/icons';
interface UserRow {
id: string;
name: string;
email: string;
role: string;
}
const users: UserRow[] = [
{ id: '1', name: 'John Smith', email: 'john@example.com', role: 'Admin' },
{ id: '2', name: 'Sarah Johnson', email: 'sarah@example.com', role: 'Editor' },
{ id: '3', name: 'Mike Wilson', email: 'mike@example.com', role: 'Viewer' },
{ id: '4', name: 'Emily Davis', email: 'emily@example.com', role: 'Editor' },
];
const columns: Column<UserRow>[] = [
{ key: 'name', title: 'Name', width: '220px' },
{ key: 'email', title: 'Email', width: '260px' },
{ key: 'role', title: 'Role', width: '140px' },
{
key: 'actions',
title: '',
width: '92px',
align: 'right',
cellVariant: 'actions',
render: (_value, row) => (
<Flex gap="4xs">
<IconButton variant="tertiary" size="small" icon={<PenOutline />} aria-label={`Edit ${row.name}`} />
<IconButton variant="tertiary" size="small" icon={<TrashOutline />} aria-label={`Delete ${row.name}`} />
</Flex>
),
},
];
export default function DataTableFloatingActionsExample() {
return (
<Box maxW={400} overflow="hidden" border="var(--border-sm) solid var(--border-neutral-tertiary)" borderRadius="xs">
<DataTable columns={columns} data={users} rowKey="id" flush />
</Box>
);
}Render different actions based on row status or role. This example mixes text buttons and icon buttons inside the same floating action bar.
Name | Email | Role | Status | |
|---|---|---|---|---|
John Smith | john@example.com | Admin | active | |
Sarah Johnson | sarah@example.com | Editor | active | |
Mike Wilson | mike@example.com | Viewer | inactive | |
Emily Davis | emily@example.com | Editor | pending |
"use client";
import { Badge, Box, Button, DataTable, Flex, IconButton, type Column } from '@photonix/ultimate';
import { PenOutline, SettingsOutline } from '@photonix/icons';
interface UserRow {
id: string;
name: string;
email: string;
role: string;
status: 'active' | 'pending' | 'inactive';
}
const users: UserRow[] = [
{ id: '1', name: 'John Smith', email: 'john@example.com', role: 'Admin', status: 'active' },
{ id: '2', name: 'Sarah Johnson', email: 'sarah@example.com', role: 'Editor', status: 'active' },
{ id: '3', name: 'Mike Wilson', email: 'mike@example.com', role: 'Viewer', status: 'inactive' },
{ id: '4', name: 'Emily Davis', email: 'emily@example.com', role: 'Editor', status: 'pending' },
];
const columns: Column<UserRow>[] = [
{ key: 'name', title: 'Name', width: '250px' },
{ key: 'email', title: 'Email', width: 'auto' },
{ key: 'role', title: 'Role', width: '150px' },
{
key: 'status',
title: 'Status',
width: '120px',
render: (val) => <Badge color={val === 'active' ? 'green' : val === 'pending' ? 'orange' : 'gray'} label={String(val)} />,
},
];
export default function DataTableContextualActionsExample() {
return (
<Box maxW={400} overflow="hidden" border="var(--border-sm) solid var(--border-neutral-tertiary)" borderRadius="xs">
<DataTable
columns={columns}
data={users}
rowKey="id"
flush
rowActions={(row) => {
if (row.role === 'Admin') {
return (
<Flex gap="4xs">
<Button variant="secondary" size="small">Manage</Button>
<IconButton variant="tertiary" size="small" icon={<SettingsOutline />} aria-label={`Open settings for ${row.name}`} />
</Flex>
);
}
return (
<Flex gap="4xs">
<Button variant="secondary" size="small">Review</Button>
{row.status === 'pending' && <Button variant="secondary" size="small">Approve</Button>}
<IconButton variant="tertiary" size="small" icon={<PenOutline />} aria-label={`Edit ${row.name}`} />
</Flex>
);
}}
/>
</Box>
);
}Use cellVariant to automatically format common data types (ID, Money, Date, etc.).
User | ID | Revenue | Last Active | ||
|---|---|---|---|---|---|
J John Smith Admin | 1 | 12500 | 15/03/2024, 10:00:00 | ||
S Sarah Johnson Editor | 2 | 8900 | 14/03/2024, 11:30:00 | ||
M Mike Wilson Viewer | 3 | 3200 | 13/03/2024, 09:15:00 | ||
E Emily Davis Editor | 4 | 15800 | 12/03/2024, 14:45:00 |
"use client";
import { Avatar, Box, DataTable, Flex, IconButton, Text, type Column } from '@photonix/ultimate';
import { InformationOutline } from '@photonix/icons';
interface UserRow {
id: string;
name: string;
role: string;
revenue: number;
date: string;
}
const users: UserRow[] = [
{ id: '1', name: 'John Smith', role: 'Admin', revenue: 12500, date: '2024-03-15T10:00:00Z' },
{ id: '2', name: 'Sarah Johnson', role: 'Editor', revenue: 8900, date: '2024-03-14T11:30:00Z' },
{ id: '3', name: 'Mike Wilson', role: 'Viewer', revenue: 3200, date: '2024-03-13T09:15:00Z' },
{ id: '4', name: 'Emily Davis', role: 'Editor', revenue: 15800, date: '2024-03-12T14:45:00Z' },
];
const columns: Column<UserRow>[] = [
{
key: 'avatar',
title: 'User',
width: '200px',
cellVariant: 'avatar',
render: (_value, row) => (
<Flex gap="sm" align="center">
<Avatar name={row.name} size="32" />
<Box>
<Text variant="body-sm" weight="medium">{row.name}</Text>
<Text variant="body-sm" color="secondary">{row.role}</Text>
</Box>
</Flex>
),
},
{ key: 'id', title: 'ID', width: '80px', cellVariant: 'id' },
{ key: 'revenue', title: 'Revenue', width: '150px', cellVariant: 'money', sortable: true },
{ key: 'date', title: 'Last Active', width: '220px', cellVariant: 'date', sortable: true },
{
key: 'actions',
title: '',
width: '60px',
align: 'right',
cellVariant: 'actions',
render: () => <IconButton variant="tertiary" size="small" icon={<InformationOutline />} aria-label="View details" />,
},
];
export default function DataTableCellVariantsExample() {
return <DataTable columns={columns} data={users} rowKey="id" bordered />;
}Choose the density that best fits your interface.
Name | Email | Role | Status |
|---|---|---|---|
John Smith | john@example.com | Admin | active |
Sarah Johnson | sarah@example.com | Editor | active |
Name | Email | Role | Status |
|---|---|---|---|
John Smith | john@example.com | Admin | active |
Sarah Johnson | sarah@example.com | Editor | active |
Name | Email | Role | Status |
|---|---|---|---|
John Smith | john@example.com | Admin | active |
Sarah Johnson | sarah@example.com | Editor | active |
"use client";
import { Badge, Box, DataTable, Heading, Stack, type Column } from '@photonix/ultimate';
interface UserRow {
id: string;
name: string;
email: string;
role: string;
status: 'active' | 'pending' | 'inactive';
}
const users: UserRow[] = [
{ id: '1', name: 'John Smith', email: 'john@example.com', role: 'Admin', status: 'active' },
{ id: '2', name: 'Sarah Johnson', email: 'sarah@example.com', role: 'Editor', status: 'active' },
];
const columns: Column<UserRow>[] = [
{ key: 'name', title: 'Name', width: '250px' },
{ key: 'email', title: 'Email', width: 'auto' },
{ key: 'role', title: 'Role', width: '150px' },
{
key: 'status',
title: 'Status',
width: '120px',
render: (val) => <Badge color={val === 'active' ? 'green' : val === 'pending' ? 'orange' : 'gray'} label={String(val)} />,
},
];
export default function DataTableSizesExample() {
return (
<Stack gap="xl" w="100%">
<Box>
<Heading as="h3" style={{ marginBottom: '8px' }}>Small</Heading>
<DataTable columns={columns} data={users} rowKey="id" size="small" />
</Box>
<Box>
<Heading as="h3" style={{ marginBottom: '8px' }}>Medium (Default)</Heading>
<DataTable columns={columns} data={users} rowKey="id" size="medium" />
</Box>
<Box>
<Heading as="h3" style={{ marginBottom: '8px' }}>Large</Heading>
<DataTable columns={columns} data={users} rowKey="id" size="large" />
</Box>
</Stack>
);
}Combine different props to achieve the look you need.
Name | Email | Role | Status |
|---|---|---|---|
John Smith | john@example.com | Admin | active |
Sarah Johnson | sarah@example.com | Editor | active |
Mike Wilson | mike@example.com | Viewer | inactive |
Emily Davis | emily@example.com | Editor | pending |
Name | Email | Role | Status |
|---|
No records found for your search.
"use client";
import { Badge, Box, DataTable, Heading, Stack, Text, type Column } from '@photonix/ultimate';
import { InformationOutline } from '@photonix/icons';
interface UserRow {
id: string;
name: string;
email: string;
role: string;
status: 'active' | 'pending' | 'inactive';
}
const users: UserRow[] = [
{ id: '1', name: 'John Smith', email: 'john@example.com', role: 'Admin', status: 'active' },
{ id: '2', name: 'Sarah Johnson', email: 'sarah@example.com', role: 'Editor', status: 'active' },
{ id: '3', name: 'Mike Wilson', email: 'mike@example.com', role: 'Viewer', status: 'inactive' },
{ id: '4', name: 'Emily Davis', email: 'emily@example.com', role: 'Editor', status: 'pending' },
];
const columns: Column<UserRow>[] = [
{ key: 'name', title: 'Name', width: '250px' },
{ key: 'email', title: 'Email', width: 'auto' },
{ key: 'role', title: 'Role', width: '150px' },
{
key: 'status',
title: 'Status',
width: '120px',
render: (val) => <Badge color={val === 'active' ? 'green' : val === 'pending' ? 'orange' : 'gray'} label={String(val)} />,
},
];
export default function DataTableStylesExample() {
return (
<Stack gap="xl" w="100%">
<Box>
<Heading as="h3" style={{ marginBottom: '8px' }}>Striped & Hoverable</Heading>
<DataTable columns={columns} data={users} rowKey="id" striped hoverable />
</Box>
<Box>
<DataTable
columns={columns}
data={[]}
rowKey="id"
emptyContent={
<Stack align="center" gap="sm">
<InformationOutline size={32} color="secondary" />
<Text color="secondary">No records found for your search.</Text>
</Stack>
}
/>
</Box>
</Stack>
);
}