Table
Displays structured data in a row-and-column grid with sorting, row selection, multi-select, and a loading state. It can be wired together with a pagination component.
columns / data support a declarative attribute channel: pass a JSON string directly to render the header and data rows (invalid JSON falls back to the empty state), while the property channel (assigning arrays/objects, property takes precedence) remains available and can be serialized into an SSR snapshot.
Basic Usage (with Sorting)
Sortable columns
Click a sortable column header to cycle through ascending / descending / no sort.
Column Alignment and Width
Alignment and width
Controlled Sorting and Row Selection
Initial sort and selection
sort-key / sort-order control the sort; selected highlights the selected row (clicking a row toggles the selection).
Multi-Select
Row multi-select (checkable)
The header checkbox selects / clears all rows at once; row checkboxes toggle individually. Selection changes emit oas-check.
Integration with Pagination
Table + pagination
Table data is sliced into 5 rows per page; on page change the data attribute is updated via the oas-change event and the table re-renders.
Fixed Columns
Left fixed column
Left/right fixed columns + sticky header
In the column config, fixed: 'left' | 'right' makes that column's header and cells position: sticky (the left / right offset is accumulated automatically from column widths); the remaining columns scroll horizontally, and the header always stays sticky.
Large Data Sets (Virtual Scroll)
Virtual scroll with 10k rows
Setting height enables virtual scrolling (with a fixed row-height): only rows within the visible window are rendered. It works together with fixed columns, sorting, and multi-select; scrolling emits oas-scroll.
Stripes and Borders
Striped rows (stripe)
Full border (bordered)
Set stripe to alternate the background of odd/even rows, or bordered to draw a full grid border around the cells.
Summary Row
Summary row (summary)
The summary attribute is a JSON array [{ key, type: 'sum' | 'avg' | 'count', label? }] rendered as a summary row at the table footer: label is shown in the first non-aggregated column, and each aggregated value in its corresponding column. You can also write summary: 'sum' | 'avg' | 'count' directly on a column config.
Expandable Rows
Expandable rows (expand field)
When a row's data has a non-empty expand field, an expand column appears at the end of the table; clicking the button expands the whole row to show custom content. The expanded state is stored in the expanded attribute (a comma-separated set of keys), and toggling emits oas-expand.
Controlled expansion (expanded attribute)
expanded is a controlled attribute (a comma-separated set of keys): pre-expanded rows open on the first render, and the host can add or remove keys at any time to drive the expansion state (shared by tree parent rows and expandable rows).
Tree Data
Tree data (children)
Rows with a children array are rendered as a tree: parent rows show an expand button in the first column, and child rows are indented by depth. The expanded state is stored in the same expanded attribute, and toggling emits oas-expand.
Loading State
Loading state
With the loading attribute, the header stays visible and the data area shows placeholder rows; removing the attribute restores the data.
Empty State
Empty data
Custom empty text
Events
Sort and click events
Sort: none · Row: —
API
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
bordered | Full border: draws a grid outline around cells (the outer frame is built in) | — | — |
checkable | Enables checkbox multi-select | boolean | — |
columns | Column config [{ key, title, sortable?, width?, align?, fixed?, render?, summary? }], JSON string (declarative attribute channel; property assignment takes precedence) | TableColumn[] | string | [] |
data | Row data [{ [key]: value, children?, expand? }], JSON string (declarative attribute channel; property assignment takes precedence) | Array<Record<string, unknown>> | string | [] |
empty-text | Empty state text | — | — |
expanded | Set of expanded row keys (comma-separated; shared by tree parent rows and expandable rows) | string | — |
height | Virtual scroll viewport height (px); when set, only visible-window rows plus head/tail placeholders are rendered | string | 320 |
loading | Loading state: shows placeholder rows in the data area (header retained) | boolean | — |
row-height | Fixed row height for virtual scrolling (px) | string | 40 |
row-key | Unique key field of a row | string | key |
selected | Set of selected row keys (comma-separated) | string | — |
sort-key | Controlled sort; sort-order is asc / desc / empty | string | — |
sort-order | Controlled sort; sort-order is asc / desc / empty | SortOrder | — |
stripe | Zebra striping: alternating light background for odd/even rows | boolean | — |
summary | Summary config [{ key, type: 'sum'|'avg'|'count', label? }], JSON string | string | — |
Events
| Event | Description |
|---|---|
oas-check | Checkbox selection change, detail: { keys: string[] } |
oas-expand | Row expand/collapse (tree child rows or expandable content rows), detail: { key, expanded } |
oas-row-click | Row click (also toggles selection when not checkable), detail: { row, key } |
oas-scroll | Virtual scroll event (rAF throttled), detail: { scrollTop, start, end } |
oas-sort-change | Sort change, detail: { key, order: 'asc' | 'desc' | '' } |
Note:
columns.renderis a function type and can only be assigned via the property from JS — it cannot be expressed as a JSON string. Forfixedcolumns it is recommended to declarewidthexplicitly (sticky offsets fall back to 100px when omitted). Summary can also be written directly on a column assummary: 'sum' | 'avg' | 'count';children(tree child rows) andexpand(expandable row content) are both row data fields.
The loading placeholder row is exposed as ::part(loading-row), the summary row as ::part(summary-row), and the expandable content row as ::part(expand-row); each can be styled independently.