Table
Rows of data: sort, paging, a sticky header, empty and loading states.
Example
| Round | |||
|---|---|---|---|
| r_8f2c91 | Fish on! | 2.00 EUR | 18.40 EUR |
| r_4a7d10 | Cash Crop | 1.00 EUR | 0.00 EUR |
| r_c11e58 | Sands of Gold | 5.00 EUR | 1,250.00 EUR |
| r_09b3f2 | Midnight Hex | 2.00 EUR | 3.60 EUR |
<script lang="ts">
import { Table, useUiTranslator } from '@onlywin/ui-svelte';
interface IRound {
readonly bet: number;
readonly game: string;
readonly id: string;
readonly win: number;
}
const rows: ReadonlyArray<IRound> = [
{ bet: 200, game: 'Fish on!', id: 'r_8f2c91', win: 1840 },
{ bet: 100, game: 'Cash Crop', id: 'r_4a7d10', win: 0 },
{ bet: 500, game: 'Sands of Gold', id: 'r_c11e58', win: 125_000 },
{ bet: 200, game: 'Midnight Hex', id: 'r_09b3f2', win: 360 },
{ bet: 100, game: 'Cat Story', id: 'r_7e66a4', win: 150 },
];
const tr = useUiTranslator();
// Money in minor units, formatted for the reader's language.
const euro = (minor: number): string => tr().money(minor, 'EUR');
</script>
<Table
caption="Latest rounds"
captionVisible
{rows}
rowKey={(row) => row.id}
pageSize={4}
columns={[
{ key: 'id', label: 'Round', mono: true },
{ key: 'game', label: 'Game', sortable: true },
{
align: 'end',
format: (row) => euro(row.bet),
key: 'bet',
label: 'Bet',
sortable: true,
},
{
align: 'end',
format: (row) => euro(row.win),
key: 'win',
label: 'Win',
sortable: true,
},
]}
/>Usage
Do
- Sort on the client for small sets; pass onSortChange and total for server data.
- Align money and counts to the end.
Don’t
- Do not put forms in table cells.
- Do not hide the caption; keep it for screen readers at least.
Accessibility
- A real <table> with a caption; sorted columns carry aria-sort; sort buttons are named “Sort by …”.
- Loading sets aria-busy and announces it; numbers align to the end and use tabular figures.
Keyboard
| Keys | Action |
|---|---|
Enter, Space | Activate |
Tab, Shift+Tab | Move focus in and out |
Props
The same props in both frameworks. In React, class is className, events are camelCase (onClick),
content passed as Svelte snippets is a ReactNode prop, every bindable value has a default… twin for uncontrolled use,
and elementRef reaches the DOM element.
| Prop | Type | Default | Description |
|---|---|---|---|
caption
*required | string | — | The table's name; visually hidden unless `captionVisible`. |
captionVisible | boolean | false | |
cell | Snippet<[TRow, IUiTableColumn<TRow>]> | — | A custom cell; default the column's formatted text. |
columns
*required | ReadonlyArray<IUiTableColumn<TRow>> | — | |
empty | Snippet | — | Shown when there are no rows; default an empty state. |
emptyTitle | string | — | |
loading | boolean | false | |
onPageChange | (page: number) => void | — | |
onSortChange | (sort: IUiTableSort | null) => void | — | Server-side sorting: the table shows rows as given and reports clicks here. |
page | number | 1 |
Bindable in Svelte; defaultPage in React.
|
pageSize | number | — | Rows per page; without it the table does not page. |
rowKey
*required | (row: TRow) => string | — | |
rows
*required | ReadonlyArray<TRow> | — | |
sort | IUiTableSort | null | null |
Bindable in Svelte; defaultSort in React.
|
sticky | boolean | true | |
total | number | — | Server-side paging: the total row count, `rows` being the current page. |