Photonix

DataTable

A feature-rich data grid with sorting, selection, resizing, and responsive layouts.

Preview

Name
Email
Status
Jane Cooper
jane@example.com
active
Wade Warren
wade@example.com
pending
Esther Howard
esther@example.com
inactive
Usage
"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" />;
}

Component API

DataTable

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

Column

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.

Showcase

Row Selection

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
Row Selection
"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>
    );
}

Sorting

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
Sorting
"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); }} />;
}

Pagination

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
1-3of 6
Items per page
Pagination
"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 }} />;
}

Loading State

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
Loading State
"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>
    );
}

Sticky Columns

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
Sticky Columns
"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>
    );
}

Floating Row Actions

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
Floating Row Actions
"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>
    );
}

Contextual Actions

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
Contextual Actions
"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>
    );
}

Cell Variants

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
Cell Variants
"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 />;
}

Sizes & Density

Choose the density that best fits your interface.

Small

Name
Email
Role
Status
John Smith
john@example.com
Admin
active
Sarah Johnson
sarah@example.com
Editor
active

Medium (Default)

Name
Email
Role
Status
John Smith
john@example.com
Admin
active
Sarah Johnson
sarah@example.com
Editor
active

Large

Name
Email
Role
Status
John Smith
john@example.com
Admin
active
Sarah Johnson
sarah@example.com
Editor
active
Sizes & Density
"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>
    );
}

Style Variations

Combine different props to achieve the look you need.

Striped & Hoverable

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.

Style Variations
"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>
    );
}

On this page

Preview
Component API
Showcase
Row Selection
Sorting
Pagination
Loading State
Sticky Columns
Floating Row Actions
Contextual Actions
Cell Variants
Sizes & Density
Style Variations
Photonix UI - React Components, Templates & Figma Design System