DataTable

An advanced React table that supports filtering, sorting, and pagination out of the box.
1<DataTableDemo />

Usage

1import {
2 DataTable,
3 DataTableColumnDef,
4 DataTableQuery,
5 DataTableSort,
6 useDataTable,
7 EmptyFilterValue
8} from "@raystack/apsara";

DataTable Props

Prop

Type

DataTable.DisplayControls Props

Prop

Type

DataTable.Filters Props

Prop

Type

DataTableQuery Interface

Prop

Type

DataTableColumn Interface

Prop

Type

DataTable.Content Props

Prop

Type

Examples

Basic Usage

1import { DataTable } from "@raystack/apsara";
2
3const columns = [
4 {
5 accessorKey: "name",
6 header: "Name",
7 columnType: "text",
8 enableSorting: true,
9 },
10 {
11 accessorKey: "age",
12 header: "Age",
13 columnType: "number",
14 enableSorting: true,
15 },
16];
17const data = [
18 { name: "John Doe", age: 30 },
19 { name: "Jane Smith", age: 25 },
20];
21function MyTable() {
22 return (
23 <DataTable
24 columns={columns}
25 data={data}
26 defaultSort={{ key: "name", order: "asc" }}>
27 <DataTable.Toolbar />
28 <DataTable.Content />
29 </DataTable>
30 );
31}

Column Configuration

Columns can be configured with various options:

1interface DataTableColumnDef<TData, TValue> {
2 accessorKey: string; // Key to access data
3 header: string; // Column header text
4 columnType: "text" | "number" | "date" | "select"; // Data type
5 enableSorting?: boolean; // Enable sorting
6 enableColumnFilter?: boolean; // Enable filtering
7 enableHiding?: boolean; // Enable column visibility toggle
8 enableGrouping?: boolean; // Enable grouping
9 filterOptions?: FilterSelectOption[]; // Options for select filter
10 defaultHidden?: boolean; // Hide column by default
11}

Filtering

The DataTable supports multiple filter types:

Filter types:

  • Text: equals, not equals, contains,
  • Number: equals, not equals, less than, less than or equal, greater than, greater than or equal
  • Date: equals, not equals, before, on or before, after, on or after
  • Select: equals, not equals

Sorting

Enable column sorting:

1const columns = [
2 {
3 accessorKey: "name",
4 header: "Name",
5 enableSorting: true,
6 },
7];

Grouping

Group rows by same column data:

1const columns = [
2 {
3 accessorKey: "category",
4 header: "Category",
5 enableGrouping: true,
6 showGroupCount: true,
7 },
8];

Server-side Integration

1function ServerTable() {
2 const [data, setData] = useState([]);
3 const [query, setQuery] = useState();
4 const [isLoading, setIsLoading] = useState(false);
5 const handleQueryChange = async (query: DataTableQuery) => {
6 setIsLoading(true);
7 setQuery(query);
8 const response = await fetchData(query);
9 setData(response.data);
10 setIsLoading(false);
11 };
12 return (
13 <DataTable
14 data={data}
15 query={query}
16 columns={columns}
17 isLoading={isLoading}
18 mode="server"
19 onTableQueryChange={handleQueryChange}>
20 <DataTable.Toolbar />
21 <DataTable.Content />
22 </DataTable>
23 );
24}

Custom Styling

1const columns = [
2 {
3 accessorKey: "name",
4 header: "Name",
5 classNames: {
6 cell: "custom-cell",
7 header: "custom-header",
8 },
9 styles: {
10 cell: { fontWeight: "bold" },
11 header: { backgroundColor: "#f5f5f5" },
12 },
13 },
14];

Custom Cell Rendering

1const columns = [
2 {
3 accessorKey: "status",
4 header: "Status",
5 cell: ({ row }) => (
6 <Badge status={row.original.status}>{row.original.status}</Badge>
7 ),
8 },
9];

Using DataTable Filter

The DataTable.Filters component can be used separately to filter data for custom views.

1<DataTable
2data={data}
3query={query}
4columns={columns}
5mode="server"
6onTableQueryChange={handleQueryChange}>
7 <DataTable.Filters />
8</DataTable>

Using DataTable Display Controls

The DataTable.DisplayControls component can be used separately to display the display controls for custom views.

1<DataTable
2data={data}
3query={query}
4columns={columns}
5mode="server"
6onTableQueryChange={handleQueryChange}
7onColumnVisibilityChange={handleColumnVisibilityChange}>
8 <DataTable.DisplayControls />
9</DataTable>

The DataTable.Search component provides search functionality that automatically integrates with the table query. By default, it is disabled in zero state (when no data and no filters/search applied).

1<DataTable
2 data={data}
3 columns={columns}
4 defaultSort={{ name: "name", order: "asc" }}>
5 <DataTable.Search />
6 <DataTable.Content />
7</DataTable>

Search Auto-Disable Behavior

By default, DataTable.Search is automatically disabled in zero state to provide a better user experience. You can override this behavior:

1// Default: disabled in zero state
2<DataTable.Search />
3
4// Override: always enabled
5<DataTable.Search autoDisableInZeroState={false} />
6
7// Manual control: explicitly disable
8<DataTable.Search disabled={true} />

The search will be automatically enabled when:

  • Data exists in the table
  • Filters are applied
  • A search query is already present

Empty States

The DataTable supports two types of empty states to provide better user experience:

Zero State

Zero state is shown when no data has been fetched initially (no filters or search applied). In this state, the filter bar is automatically hidden.

1import { DataTable, EmptyState } from "@raystack/apsara";
2import { OrganizationIcon } from "@raystack/apsara/icons";
3
4<DataTable
5 data={[]}
6 columns={columns}
7 defaultSort={{ name: "name", order: "asc" }}>
8 <DataTable.Toolbar />
9 <DataTable.Content
10 zeroState={
11 <EmptyState
12 icon={<OrganizationIcon />}
13 heading="No users yet"
14 subHeading="Get started by creating your first user."
15 />
16 }
17 />
18</DataTable>

Empty State

Empty state is shown when initial data exists but no results match after applying filters or search. In this state, the filter bar remains visible so users can adjust their filters.

1import { DataTable, EmptyState } from "@raystack/apsara";
2import { OrganizationIcon, FilterIcon } from "@raystack/apsara/icons";
3
4<DataTable
5 data={initialData}
6 columns={columns}
7 defaultSort={{ name: "name", order: "asc" }}>
8 <DataTable.Toolbar />
9 <DataTable.Search />
10 <DataTable.Content
11 zeroState={
12 <EmptyState
13 icon={<OrganizationIcon />}
14 heading="No users yet"
15 subHeading="Get started by creating your first user."
16 />
17 }
18 emptyState={
19 <EmptyState
20 icon={<FilterIcon />}
21 heading="No users found"
22 subHeading="We couldn't find any matches for that keyword or filter. Try alternative terms or check for typos."
23 />
24 }
25 />
26</DataTable>

Fallback Behavior

  • If zeroState is not provided, it falls back to emptyState
  • If neither zeroState nor emptyState is provided, a default empty state is shown
  • The filter bar visibility is automatically controlled based on the state

Custom Empty State Content

You can provide custom React components for both states:

1import { DataTable, EmptyState, Flex, Text, Button } from "@raystack/apsara";
2import { OrganizationIcon, FilterIcon } from "@raystack/apsara/icons";
3
4<DataTable.Content
5 zeroState={
6 <Flex direction="column" gap={4} align="center" style={{ padding: "40px" }}>
7 <OrganizationIcon width={48} height={48} style={{ opacity: 0.5 }} />
8 <Flex direction="column" gap={2} align="center">
9 <Text size={4} weight="medium">
10 No data available
11 </Text>
12 <Text size={2} style={{ color: "var(--rs-color-text-subtle)" }}>
13 There are no users in the system. Create your first user to get started.
14 </Text>
15 </Flex>
16 <Button size="small">Create User</Button>
17 </Flex>
18 }
19 emptyState={
20 <EmptyState
21 icon={<FilterIcon />}
22 heading="No matches found"
23 subHeading="Try adjusting your filters or search query."
24 />
25 }
26/>