Table
A fully accessible, theme-aware, and sortable table component for displaying structured data in a clean and responsive way.
Usage
Basic usage
import { Table } from '@nofinite/nui';
const columns = [
{ key: 'name', label: 'Name', sortable: true },
{ key: 'age', label: 'Age', sortable: true },
{ key: 'role', label: 'Role' },
] as const;
const data = [
{ name: 'Sam', age: 21, role: 'Engineer' },
{ name: 'John', age: 30, role: 'Manager' },
{ name: 'Dev', age: 25, role: 'Designer' },
];
<Table columns={columns} data={data} />;
With typical interaction
<Table
columns={columns}
data={data}
emptyText="No employees found"
className="custom-table"
/>
Variants
Table supports sortable and non-sortable columns.
<Table columns={columns} data={data} />
<Table columns={columns} data={data} /> // all non-sortable columns
Available variants:
sortable– Columns can be clicked to sort data ascending/descending.non-sortable– Static columns without sorting functionality.
Guidelines:
- Use sortable columns for data where order matters.
- Use non-sortable for static or categorical data.
Sizes
Table does not have size variants, but column widths adjust automatically to content. Use CSS for further customization.
<Table className="w-full" columns={columns} data={data} />
States
<Table columns={columns} data={[]} emptyText="No records" />
empty– Displays a message when there is no data.hover– Row highlights on hover for better visibility.sorted– Visual indication for sorted columns with ascending/descending arrows.
Native Props / Composition
<Table className="my-custom-table" data-testid="employee-table">
{/* content rendered via columns/data */}
</Table>
Supports className for custom styling, and any additional native div or table props can be forwarded as needed.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns | TableColumn<T>[] | — | Column definitions including key, label, sortable |
data | T[] | — | Array of objects representing table rows |
emptyText | string | "No data available" | Message shown when there is no data |
className | string | "" | Additional CSS classes for the table |
Column props (TableColumn<T>):
| Prop | Type | Default | Description |
|---|---|---|---|
key | keyof T | — | Property key in the data object |
label | string | — | Column header text |
sortable | boolean | false | Whether the column supports sorting |
Behavior Notes
- Clicking a sortable column cycles through ascending → descending → unsorted.
- Sorting is applied client-side and does not mutate the original data array.
- Non-sortable columns ignore clicks.
- Table supports reduced motion preferences for accessibility.
<Table columns={columns} data={data} />
Accessibility
- Renders as a semantic
<table>with<thead>and<tbody>. - Sort buttons are focusable and accessible via keyboard.
aria-sortis implicitly indicated via visual arrow indicators.- Empty state uses a single cell spanning all columns for screen reader clarity.
<Table columns={columns} data={[]} aria-label="Employee Table" />
Layout
- Full-width by default, scrollable horizontally on overflow.
- Rows highlight on hover.
- Use
classNameor custom CSS for further layout adjustments.
<Table className="w-full" columns={columns} data={data} />
Best Practices
Do
- Use sortable columns for numeric or date data.
- Provide meaningful
emptyTextfor better UX. - Customize styles with
classNameas needed.
Don’t
- Overload with too many columns; keep tables readable.
- Use Table for non-tabular layouts.
- Hide important data in unsortable columns without clear labels.