Table
A responsive table component with sorting, filtering, and pagination support.
Installation
npx vayu-ui init #one time onlynpx vayu-ui add tablenpx vayu-ui add -t table #with test case needsUsage
Table Example
Default Table
Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| Total | $1,750.00 | ||
Table with Selected Row
Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
Table with Sortable Columns
Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
Table with Selectable Rows
Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
Table with Actions
Invoice | Status | Method | Amount | Actions |
|---|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 | |
| INV002 | Pending | PayPal | $150.00 | |
| INV003 | Unpaid | Bank Transfer | $350.00 | |
| INV004 | Paid | Credit Card | $450.00 | |
| INV005 | Paid | PayPal | $550.00 |
<Table aria-label="Invoice List">
<Table.Caption>A list of your recent invoices.</Table.Caption>
<Table.Head>
<Table.Row>
<Table.Header className="w-[100px]">Invoice</Table.Header>
<Table.Header>Status</Table.Header>
<Table.Header>Method</Table.Header>
<Table.Header className="text-right">Amount</Table.Header>
</Table.Row>
</Table.Head>
<Table.Body>
{invoices.map((invoice) => (
<Table.Row key={invoice.invoice}>
<Table.Cell className="font-medium">{invoice.invoice}</Table.Cell>
<Table.Cell>{invoice.paymentStatus}</Table.Cell>
<Table.Cell>{invoice.paymentMethod}</Table.Cell>
<Table.Cell className="text-right">{invoice.totalAmount}</Table.Cell>
</Table.Row>
))}
</Table.Body>
<Table.Footer>
<Table.Row>
<Table.Cell colSpan={3}>Total</Table.Cell>
<Table.Cell className="text-right">$750.00</Table.Cell>
</Table.Row>
</Table.Footer>
</Table>Anatomy
import { Table } from 'vayu-ui';
<Table aria-label="Your table description">
<Table.Caption>Table summary for screen readers.</Table.Caption>
<Table.Head>
<Table.Row>
<Table.Header>Column A</Table.Header>
<Table.Header>Column B</Table.Header>
</Table.Row>
</Table.Head>
<Table.Body>
<Table.Row>
<Table.Cell>Data A1</Table.Cell>
<Table.Cell>Data B1</Table.Cell>
</Table.Row>
</Table.Body>
<Table.Footer>
<Table.Row>
<Table.Cell>Total</Table.Cell>
<Table.Cell>$100.00</Table.Cell>
</Table.Row>
</Table.Footer>
</Table>;- Table — Root container. Wraps a native
<table>inside a scrollable container with border and shadow. - Table.Caption — Accessible caption element. Supports
visuallyHiddento hide visually while remaining readable by screen readers. - Table.Head —
<thead>section containing column header rows. - Table.Body —
<tbody>section containing data rows. Supportsemptyprop to enablearia-liveannouncements. - Table.Footer —
<tfoot>section for summary or totals rows. - Table.Row —
<tr>row element. Supportsselectableandselectedfor interactive row selection. - Table.Header —
<th>header cell with sort icon support viasortableandaria-sortprops. - Table.Cell —
<td>data cell with support forrowSpan,colSpan, and accessibility indexing.
Accessibility
- Keyboard Support:
Tab— Moves focus to the next focusable element. Selectable rows (selectable) receivetabIndex={0}.Enter/Space— Activates a selectable row (selection handling is user-implemented).Enter/Space— Activates a sortable header column (sort handling is user-implemented).
- ARIA Attributes:
aria-labelonTableprovides an accessible name for the table.aria-describedbyonTablereferences an external description element.aria-colcountandaria-rowcountonTablefor large or virtualized tables.aria-sortonTable.Headerreflects the current sort state (ascending,descending,none).aria-selectedonTable.Rowindicates selection state whenselectableis set.aria-rowindexonTable.Rowfor row position in large tables.aria-colindexonTable.HeaderandTable.Cellfor column position.aria-live="polite"onTable.Bodywhenemptyis true, announcing empty state changes.headersonTable.Celllinks to associated header cell IDs.- Sort indicator icons are marked
aria-hidden="true"since state is conveyed viaaria-sort.
- Focus Behavior:
- Selectable rows show a visible focus ring on
focus-visible. - Sortable headers show a visible focus ring on
focus-visible. - Focus indicators use the design system focus token (
ring-focus) with offset.
- Selectable rows show a visible focus ring on
Screen reader behavior
When a screen reader encounters the table, it announces the accessible name (from aria-label or Table.Caption) and describes the table structure. The screen reader reads column headers as the user navigates across rows, using the scope="col" attribute on Table.Header to associate headers with their columns. For sortable columns, the screen reader announces the current sort direction via aria-sort. Selectable rows announce their selection state through aria-selected. When the table body is empty and empty is set, the aria-live="polite" region announces content changes. For large tables using aria-rowcount and aria-colcount, the screen reader communicates the total table dimensions even when not all rows are rendered.
Component Folder Structure
Table/
├── Table.tsx # Root component with compound component composition
├── TableCaption.tsx # Caption with visually-hidden support
├── TableHead.tsx # <thead> section element
├── TableBody.tsx # <tbody> section with empty state aria-live
├── TableFooter.tsx # <tfoot> section element
├── TableRow.tsx # <tr> row with selectable and selected state
├── TableHeader.tsx # <th> header cell with sort icon logic
├── TableCell.tsx # <td> data cell
├── types.ts # TypeScript type definitions
├── index.ts # Re-exports all components and types
└── README.md # Component usage referenceProps
Table
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Table sections (Caption, Head, Body, Footer). |
className | string | — | Additional CSS classes. |
aria-label | string | — | Accessible name for the table. |
aria-describedby | string | — | ID of an element describing the table. |
aria-colcount | number | — | Total column count for virtualized tables. |
aria-rowcount | number | — | Total row count for virtualized tables. |
Table.Caption
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Caption content. |
className | string | — | Additional CSS classes. |
visuallyHidden | boolean | false | Hide visually but keep accessible to screen readers. |
Table.Head
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Header rows. |
className | string | — | Additional CSS classes. |
Table.Body
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Data rows. |
className | string | — | Additional CSS classes. |
empty | boolean | false | Enable aria-live for empty state announcements. |
Table.Footer
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Footer rows. |
className | string | — | Additional CSS classes. |
Table.Row
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Row cells. |
className | string | — | Additional CSS classes. |
aria-rowindex | number | — | Row position for large tables. |
selected | boolean | false | Whether the row is currently selected. |
selectable | boolean | false | Enable keyboard focus and selection cues. |
Table.Header
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Header cell content. |
className | string | — | Additional CSS classes. |
scope | "row" | "col" | "rowgroup" | "colgroup" | "col" | Scope of the header cell. |
aria-colindex | number | — | Column position for accessibility. |
aria-sort | "ascending" | "descending" | "none" | "other" | — | Current sort direction. |
sortable | boolean | false | Show sort indicator and enable interaction. |
Table.Cell
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Cell content. |
className | string | — | Additional CSS classes. |
aria-colindex | number | — | Column position for accessibility. |
aria-rowindex | number | — | Row position for accessibility. |
headers | string | — | ID of associated header cells. |