Skip to content

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

Simulate 2s loading

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

AttributeDescriptionTypeDefault
borderedFull border: draws a grid outline around cells (the outer frame is built in)
checkableEnables checkbox multi-selectboolean
columnsColumn config [{ key, title, sortable?, width?, align?, fixed?, render?, summary? }], JSON string (declarative attribute channel; property assignment takes precedence)TableColumn[] | string[]
dataRow data [{ [key]: value, children?, expand? }], JSON string (declarative attribute channel; property assignment takes precedence)Array<Record<string, unknown>> | string[]
empty-textEmpty state text
expandedSet of expanded row keys (comma-separated; shared by tree parent rows and expandable rows)string
heightVirtual scroll viewport height (px); when set, only visible-window rows plus head/tail placeholders are renderedstring320
loadingLoading state: shows placeholder rows in the data area (header retained)boolean
row-heightFixed row height for virtual scrolling (px)string40
row-keyUnique key field of a rowstringkey
selectedSet of selected row keys (comma-separated)string
sort-keyControlled sort; sort-order is asc / desc / emptystring
sort-orderControlled sort; sort-order is asc / desc / emptySortOrder
stripeZebra striping: alternating light background for odd/even rowsboolean
summarySummary config [{ key, type: 'sum'|'avg'|'count', label? }], JSON stringstring

Events

EventDescription
oas-checkCheckbox selection change, detail: { keys: string[] }
oas-expandRow expand/collapse (tree child rows or expandable content rows), detail: { key, expanded }
oas-row-clickRow click (also toggles selection when not checkable), detail: { row, key }
oas-scrollVirtual scroll event (rAF throttled), detail: { scrollTop, start, end }
oas-sort-changeSort change, detail: { key, order: 'asc' | 'desc' | '' }

Note: columns.render is a function type and can only be assigned via the property from JS — it cannot be expressed as a JSON string. For fixed columns it is recommended to declare width explicitly (sticky offsets fall back to 100px when omitted). Summary can also be written directly on a column as summary: 'sum' | 'avg' | 'count'; children (tree child rows) and expand (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.