Table
A semantic record table with sorting, pagination, row actions and loading states.
Playground and Examples use the shared browser runtime. For Service Studio inputs and event wiring, use Implementation and API.
Open OutSystems showcase ↗Implement Table in your application
Use the same setup, screen state and event mapping workflow as the existing components. These components are included in Community 1.1.0.
A semantic record table with sorting, pagination, row actions and loading states. These components are included in @blukavantui/community 1.1.0.
Prepare your local Web project
Use a TypeScript application with a CSS-capable bundler. Install @blukavantui/community@1.1.0 from npm, or install the matching downloaded archive.
// In your test application’s package.json dependencies:
"@blukavantui/community": "1.1.0"Run npm install in that test application to install the component package. Load the theme once and the component stylesheet shown in the adapter. Create an empty host in your view:
<div id="example"></div>Mount one typed instance
This reusable adapter follows the Button and TimePicker guide pattern. Its types come from the factory, so required options stay required. Attach the host first; mount once per view and retain the handle.
import { createTable, type TableOptions, type TableEvents } from '@blukavantui/community/table'
import '@blukavantui/community/theme.css'
import '@blukavantui/community/table.css'
export function mount<Row extends object>(host: HTMLElement, options: TableOptions<Row>, events: TableEvents<Row> = {}) {
const instance = createTable<Row>(host, options, events)
return { instance, update: (patch: Partial<TableOptions<Row>>) => instance.update(patch), destroy: () => instance.destroy() }
}
Connect state and updates
Table sorts and pages the supplied rows. Your application owns requests, authorization, saving and failure feedback. Read getState() after updates: sorting resets the page and data changes can clamp it without a PageChanged callback.
Use a typed Row model and unique stable row identifiers. Formatting affects visible text; numeric sorting uses the original numeric values. The example loader returns sample data until you inject your API adapter.
Sort, format and page typed rows
Use: Columns, Rows, PageSize, SortChanged, getState
Use TableOptions<Row> and keyed columns. Format changes display text; sorting compares raw values. Table sorts/paginates the supplied array only. Sorting resets Page to 1; read getState() after sorting and data changes.
Sort numeric amounts, reach the last page, then shrink Rows and confirm Page is clamped.
Handle row actions with the original row
Use: RowKey, Actions, RowAction
Use a unique stable RowKey for accessible action labels and focus. Disabled can be a Boolean or predicate. RowAction gives your application the action key and row object; route or save using your own application logic.
Activate an enabled action and confirm the correct row; ensure disabled actions cannot run.
Own loading, empty and failed requests
Use: Loading, Rows, EmptyMessage
Set Loading around your own request. This example accepts an injected loader and ignores late results after disposal or a newer request. Show safe failure feedback, retain existing rows and allow retry. No built-in server paging, editing or persistence is implied.
Test an empty result, a rejected loader, retry, and destroying the view while a load is pending.
Use the complete working example
Save this as table.ts, import its mount function and pass your attached host. It includes application state, interactive controls and a destroy handler. Pass your async loader as the second argument to exercise loading, retry and stale-response handling.
Download the editable TypeScript example ↓
Complete Table example
import { createTable, type TableOptions } from '@blukavantui/community/table'
import '@blukavantui/community/theme.css'
import '@blukavantui/community/table.css'
export interface Customer { Id: string; Name: string; Balance: number; Active: boolean }
const initialRows: Customer[] = [
{ Id: 'C-101', Name: 'Aster Studio', Balance: 1200, Active: true },
{ Id: 'C-102', Name: 'Birch Goods', Balance: 85, Active: false },
{ Id: 'C-103', Name: 'Cedar Works', Balance: 240, Active: true },
]
// Inject your own API adapter. The default loader only returns local sample data.
export function mount(host: HTMLElement, load: () => Promise<Customer[]> = async () => initialRows) {
const root = document.createElement('section')
const refresh = document.createElement('button')
refresh.type = 'button'; refresh.textContent = 'Refresh customers'
const empty = document.createElement('button')
empty.type = 'button'; empty.textContent = 'Show empty state'
const status = document.createElement('p'); status.setAttribute('role', 'status')
const target = document.createElement('div')
root.append(refresh, empty, status, target); host.append(root)
const options: TableOptions<Customer> = {
Caption: 'Customer balances', RowKey: 'Id', Rows: initialRows,
Columns: [
{ Key: 'Name', Header: 'Customer', Sortable: true },
{ Key: 'Balance', Header: 'Balance', Sortable: true, Align: 'Right',
Format: value => typeof value === 'number' ? new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(value) : '' },
],
Actions: [{ Key: 'open', Label: 'Open', Disabled: row => !row.Active }],
PageSize: 2, Striped: true, EmptyMessage: 'No customers match this view.',
}
const instance = createTable<Customer>(target, options, {
RowAction(key, row) { status.textContent = `${key}: ${row.Id} — ${row.Name}` },
SortChanged() { renderState() }, PageChanged() { renderState() },
})
function renderState() {
const state = instance.getState()
status.textContent = `Page ${state.Page}; sort ${state.SortKey || 'input order'} ${state.SortDirection}`
}
let disposed = false, request = 0
const listeners = new AbortController()
async function reload() {
const current = ++request
instance.update({ Loading: true }); status.textContent = 'Loading customers…'
try {
const rows = await load()
if (disposed || current !== request) return
instance.update({ Rows: rows, Loading: false }); renderState()
} catch {
if (disposed || current !== request) return
instance.update({ Loading: false }) // Retain previous rows and allow retry.
status.textContent = 'Could not load customers. Try Refresh again.'
}
}
refresh.addEventListener('click', () => { void reload() }, { signal: listeners.signal })
empty.addEventListener('click', () => {
++request; instance.update({ Rows: [], Loading: false }); renderState()
}, { signal: listeners.signal })
renderState()
return { instance, reload, destroy() {
disposed = true; ++request; listeners.abort(); instance.destroy(); root.remove()
} }
}
Verify behavior and dispose
- Tab reaches sortable headings, row actions and paging buttons. Activate a focused button with Enter or Space.
- Check empty/loading/error states, disabled row actions, sorting and page clamping. Test a late response after the view is removed.
- Call the example handle’s
destroy()when the view is removed. Abort your application listeners and requests; ignore any asynchronous result after disposal. - Mount again and confirm there is one instance and one callback per interaction.
Reference the native producer
In Manage Dependencies, select Table from BluKavantUi_Community_Data, together with the structures and public actions used by its API. Refresh existing references before publishing your consumer. Inherit the shared Community theme in your application's theme.
Place the Block in your screen
ExampleScreen — Screen (your application)
└─ ExistingLayout — referenced Layout Block instance (child of ExampleScreen)
└─ Content — existing slot on ExistingLayout
└─ ComponentRegion — Container (child of that slot)
└─ MainComponent — BluKavantUi_Community_Data.Table Block instance (child of ComponentRegion)Reuse your screen’s existing Layout and its content slot; do not add a second layout. If your Layout names that slot differently, use its actual content slot. ComponentRegion is a new Container; MainComponent is a referenced Block instance.
Create and bind screen state
Create local variables on ExampleScreen for the values your application changes. Use the exact native types below; lists are typed OutSystems Lists, while inputs ending in Json are Text containing the documented JSON. Bind each MainComponent.Input to its matching StateInput local. Constants can instead use the default directly. Fill required data from your Aggregate or Data Action before enabling interaction.
| MainComponent input | Screen local / native type | Initial value | Purpose |
|---|---|---|---|
| ColumnsJson | StateColumnsJson · Text | "[]" | JSON array of column definitions: Key, Header, optional Sortable and Align (Left, Center or Right). Key must match a row property. At least one column is required to render. |
| RowsJson | StateRowsJson · Text | "[]" | JSON array of row objects. Include every displayed property and a unique RowKey value when RowKey is configured. Table operates on this supplied array. |
| ActionsJson | StateActionsJson · Text | "[]" | JSON array of row actions: Key, Label and optional Boolean Disabled. Each action raises OnRowAction. Functions are not supported in native JSON. |
| Loading | StateLoading · Boolean | False | Shows the loading state in place of records. Your application loads data and clears this flag. |
| Page | StatePage · Integer | 1 | One-based current page. Keep this variable synchronized with OnPageChanged.Page. |
| SortKey | StateSortKey · Text | "" | Column key for the initial/current sort. Empty leaves the supplied row order. |
| SortDirection | StateSortDirection · Text | "Ascending" | Ascending or Descending. Keep synchronized with OnSortChanged.Direction. |
All native input defaults
| Input | Type | Default | Required |
|---|---|---|---|
| ColumnsJson | Text | "[]" | No |
| RowsJson | Text | "[]" | No |
| ActionsJson | Text | "[]" | No |
| Caption | Text | "Records" | No |
| RowKey | Text | "" | No |
| Loading | Boolean | False | No |
| EmptyMessage | Text | "No records yet." | No |
| PageSize | Integer | 0 | No |
| Page | Integer | 1 | No |
| SortKey | Text | "" | No |
| SortDirection | Text | "Ascending" | No |
| Density | Text | "Comfortable" | No |
| Striped | Boolean | False | No |
| ExtendedClass | Text | "" | No |
| EnableMotion | Boolean | False | No |
| MotionPreference | Text | "System" | No |
| UseDefaultMotionDuration | Boolean | True | No |
| MotionDurationMs | Integer | 450 | No |
| MotionEasing | Text | "standard" | No |
Create the event handlers and map every argument
For each event you use, create the named screen Client Action below. Add its listed input parameters with the exact types. Select that action on MainComponent's event property, then enter each mapping explicitly. Event arguments and screen locals are different scopes.
OnError → HandleError
Reports native runtime initialization or update errors. Show safe feedback and inspect the configuration; this is not the normal field validation event.
| Handler input | Native type | Event mapping |
|---|---|---|
| RequestedMessage | Text | RequestedMessage = Message |
Flow: Start → display the mapped error argument in your feedback region → End.
OnPageChanged → HandlePageChanged
Reports the one-based Page after navigation. Assign it to the bound Page variable.
| Handler input | Native type | Event mapping |
|---|---|---|
| RequestedPage | Integer | RequestedPage = Page |
Flow: Start → validate the requested value; assign the corresponding screen state so the Block receives it back → End.
OnRowAction → HandleRowAction
Raised by a row action. Key identifies the action and RowJson contains that row serialized as JSON. Deserialize into your own row structure before using it.
| Handler input | Native type | Event mapping |
|---|---|---|
| RequestedKey | Text | RequestedKey = Key |
| RequestedRowJson | Text | RequestedRowJson = RowJson |
Flow: Start → run your application action using the mapped event arguments → End.
For a JSON argument, use JSON Deserialize with the matching Structure or List shown in this component’s API. Do not deserialize unrelated payloads into the same structure. Keep the raw JSON only when the documented storage contract requires it.
OnSortChanged → HandleSortChanged
Reports the column Key and Direction after local sorting. Assign both to the bound SortKey and SortDirection variables.
| Handler input | Native type | Event mapping |
|---|---|---|
| RequestedKey | Text | RequestedKey = Key |
| RequestedDirection | Text | RequestedDirection = Direction |
Flow: Start → validate the requested value; assign the corresponding screen state so the Block receives it back → End.
Apply the example event flow
MainComponent.OnRowAction → HandleRowAction
Map RequestedKey = Key
Map RequestedRowJson = RowJson
Start
→ JSON Deserialize RequestedRowJson into your Customer structure
→ If RequestedKey = "open", open the authorized customer detail using its Id
→ EndPrepare the payloads
Inputs ending in Json are Text containing JSON. Define the matching application Structure/List, then use JSON Serialize. The JSON below is payload content, not an OutSystems expression literal.
ColumnsJson
Native JSON cannot carry a JavaScript Format callback. Prepare display values in your data.
[
{
"Key": "Id",
"Header": "ID"
},
{
"Key": "Name",
"Header": "Customer",
"Sortable": true
}
]RowsJson
Set RowKey to "Id". These two records are application sample data.
[
{
"Id": "C-101",
"Name": "Northwind"
},
{
"Id": "C-102",
"Name": "Alpine"
}
]ActionsJson
A row action emits Key and the complete RowJson.
[
{
"Key": "open",
"Label": "Open",
"Disabled": false
}
]Verify in your consumer
Publish the consumer, supply representative data, trigger each connected event and inspect the mapped arguments. Check a failed request, a retry and leaving/reopening the screen. The table describes the native contract; the Web recipes can contain capabilities with different native names or availability. Use these native names and the API tab as the authority for Service Studio.
Shared component motion settings
Use createMotionData from the local bluui-community/src/data-motion.ts entry. The factories retain the component’s data, options, events and methods, and add setMotion(settings?). Create the controller with createMotionController from bluui-community/src/motion.ts.
| Setting / method | Behavior |
|---|---|
mode | inherit (default), reduced, or off. The owning controller and operating system can always reduce or disable motion. |
duration | Optional finite-transition override, 0–2000 ms. Omit for default timings; zero is immediate. Reduced caps permitted fades at 200 ms. Continuous loading retains its own cadence. |
easing | Optional standard, ease-in, ease-out, ease-in-out, linear or spring. Omit for each component's default easing. |
ui.configure(settings?) | Replace collection defaults, update existing instances and cancel their unfinished decoration. Explicit instance overrides remain. Omit settings to restore component defaults. |
component.setMotion(settings?) | Replace just this instance's overrides. Omit settings to inherit the collection again. Inputs, focus, content and actions are retained. |
ui.destroy() | Dispose owned instances and their motion before destroying the controller. No global listener is added at import time. |
Validation rejects nonfinite, negative and over-2000-ms durations before changing settings. Motion follows the existing component behavior. Grid rows need stable keys; charts update their actual data series; workflow transitions retain their approval and save contracts. Charts respect EnableAnimation: false; continuous Sparkline glow keeps its own cadence and Pause control. Ripple, glow, shimmer and page-entry helpers remain explicit additions.
Open the playground motion controls · Read the motion and OutSystems integration guide
Current playground settings
Open the playground to load the local source example.Table with application state
These components are included in @blukavantui/community 1.1.0. This is the same complete example used by the implementation guide, with real controls, event handling and cleanup.
import { createTable, type TableOptions } from '@blukavantui/community/table'
import '@blukavantui/community/theme.css'
import '@blukavantui/community/table.css'
export interface Customer { Id: string; Name: string; Balance: number; Active: boolean }
const initialRows: Customer[] = [
{ Id: 'C-101', Name: 'Aster Studio', Balance: 1200, Active: true },
{ Id: 'C-102', Name: 'Birch Goods', Balance: 85, Active: false },
{ Id: 'C-103', Name: 'Cedar Works', Balance: 240, Active: true },
]
// Inject your own API adapter. The default loader only returns local sample data.
export function mount(host: HTMLElement, load: () => Promise<Customer[]> = async () => initialRows) {
const root = document.createElement('section')
const refresh = document.createElement('button')
refresh.type = 'button'; refresh.textContent = 'Refresh customers'
const empty = document.createElement('button')
empty.type = 'button'; empty.textContent = 'Show empty state'
const status = document.createElement('p'); status.setAttribute('role', 'status')
const target = document.createElement('div')
root.append(refresh, empty, status, target); host.append(root)
const options: TableOptions<Customer> = {
Caption: 'Customer balances', RowKey: 'Id', Rows: initialRows,
Columns: [
{ Key: 'Name', Header: 'Customer', Sortable: true },
{ Key: 'Balance', Header: 'Balance', Sortable: true, Align: 'Right',
Format: value => typeof value === 'number' ? new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(value) : '' },
],
Actions: [{ Key: 'open', Label: 'Open', Disabled: row => !row.Active }],
PageSize: 2, Striped: true, EmptyMessage: 'No customers match this view.',
}
const instance = createTable<Customer>(target, options, {
RowAction(key, row) { status.textContent = `${key}: ${row.Id} — ${row.Name}` },
SortChanged() { renderState() }, PageChanged() { renderState() },
})
function renderState() {
const state = instance.getState()
status.textContent = `Page ${state.Page}; sort ${state.SortKey || 'input order'} ${state.SortDirection}`
}
let disposed = false, request = 0
const listeners = new AbortController()
async function reload() {
const current = ++request
instance.update({ Loading: true }); status.textContent = 'Loading customers…'
try {
const rows = await load()
if (disposed || current !== request) return
instance.update({ Rows: rows, Loading: false }); renderState()
} catch {
if (disposed || current !== request) return
instance.update({ Loading: false }) // Retain previous rows and allow retry.
status.textContent = 'Could not load customers. Try Refresh again.'
}
}
refresh.addEventListener('click', () => { void reload() }, { signal: listeners.signal })
empty.addEventListener('click', () => {
++request; instance.update({ Rows: [], Loading: false }); renderState()
}, { signal: listeners.signal })
renderState()
return { instance, reload, destroy() {
disposed = true; ++request; listeners.abort(); instance.destroy(); root.remove()
} }
}
Mount and dispose
Call mount after the host is attached to the document. Retain the returned handle and call destroy from your view’s unmount hook.
import { mount } from './table'
const host = document.getElementById('example')
if (!host) throw new Error('Missing example host')
const view = mount(host)
// Register this with your framework/router’s unmount hook:
function disposeView() { view.destroy() }Use instance.update(patch) for changes while mounted; creating another instance on each render leaves duplicate controls.
Build with native Blocks
Configure the referenced Block in Service Studio using typed inputs, screen state and Client Actions. The Implementation tab includes the widget tree and exact event argument mappings.
Shared component motion settings
Use createMotionData from the local bluui-community/src/data-motion.ts entry. The factories retain the component’s data, options, events and methods, and add setMotion(settings?). Create the controller with createMotionController from bluui-community/src/motion.ts.
| Setting / method | Behavior |
|---|---|
mode | inherit (default), reduced, or off. The owning controller and operating system can always reduce or disable motion. |
duration | Optional finite-transition override, 0–2000 ms. Omit for default timings; zero is immediate. Reduced caps permitted fades at 200 ms. Continuous loading retains its own cadence. |
easing | Optional standard, ease-in, ease-out, ease-in-out, linear or spring. Omit for each component's default easing. |
ui.configure(settings?) | Replace collection defaults, update existing instances and cancel their unfinished decoration. Explicit instance overrides remain. Omit settings to restore component defaults. |
component.setMotion(settings?) | Replace just this instance's overrides. Omit settings to inherit the collection again. Inputs, focus, content and actions are retained. |
ui.destroy() | Dispose owned instances and their motion before destroying the controller. No global listener is added at import time. |
Validation rejects nonfinite, negative and over-2000-ms durations before changing settings. Motion follows the existing component behavior. Grid rows need stable keys; charts update their actual data series; workflow transitions retain their approval and save contracts. Charts respect EnableAnimation: false; continuous Sparkline glow keeps its own cadence and Pause control. Ripple, glow, shimmer and page-entry helpers remain explicit additions.
Open the playground motion controls · Read the motion and OutSystems integration guide
Current playground settings
Open the playground to load the local source example.createTable
Table sorts and pages the supplied rows. Your application owns requests, authorization, saving and failure feedback. Read getState() after updates: sorting resets the page and data changes can clamp it without a PageChanged callback.
import { createTable } from '@blukavantui/community/table';
import '@blukavantui/community/table.css';Load @blukavantui/community/theme.css once in your app shell.createTable<Row extends object>(host: HTMLElement, initial: TableOptions<Row>, events?: TableEvents<Row>)These components are included in @blukavantui/community 1.1.0. Required/optional and signatures come from the 1.1.0 TypeScript source. Defaults below describe runtime behavior, which may differ from the Playground’s selected example.
Options
14| Name | Type / requirement | Usage |
|---|---|---|
Columns | TableColumn<Row>[]Required | Required. Non-empty array of typed TableColumn<Row> definitions with unique Key values. Headers and formatted values render as text. |
Rows | Row[]Required | Required. Typed Row array; [] shows the empty state. Sorting copies the array without reordering your input. Rows themselves remain your objects. |
Caption | stringRequired | Required. Accessible caption naming the records. Supply a meaningful non-empty string. |
RowKey | Extract<keyof Row, string> | undefinedOptional | Default: Not set. Row property used in action labels and focus restoration. Provide unique stable values; without it the displayed page index is used. The component does not validate row-key uniqueness. |
Actions | TableAction<Row>[] | undefinedOptional | Default: []. TableAction<Row> array. Each has Key, Label and optional Disabled boolean or row predicate. RowAction receives that key and the original row object. |
Loading | boolean | undefinedOptional | Default: false. Shows loading feedback instead of records and disables paging. Your application supplies data and clears this flag; there is no fetch or persistence API. |
EmptyMessage | string | undefinedOptional | Default: "No records yet.". Text displayed for an empty Rows array while Loading is false. |
PageSize | number | undefinedOptional | Default: 0 / all rows. Omit or use zero for no page buttons. A nonzero value is clamped to an integer from 1 to 10000; paging only covers supplied rows. |
Page | number | undefinedOptional | Default: 1. One-based current page, clamped after data or page-size changes. Read getState() after programmatic updates. |
SortKey | Extract<keyof Row, string> | undefinedOptional | Default: Not set. A column Key marked Sortable. Missing/non-sortable keys retain input order. Sorting is client-side over supplied rows. |
SortDirection | "Ascending" | "Descending" | undefinedOptional | Default: "Ascending". Ascending or Descending. Numbers sort numerically; other values use natural string comparison. Null/undefined stay last in either direction. |
Density | "Compact" | "Comfortable" | undefinedOptional | Default: "Comfortable". Compact or Comfortable row spacing. |
Striped | boolean | undefinedOptional | Default: false. Alternating row backgrounds. |
ExtendedClass | string | undefinedOptional | Default: "". Additional space-separated classes on the root. Keep application CSS scoped. |
Callbacks
3| Name | Type / requirement | Usage |
|---|---|---|
RowAction | ((key: string, row: Row) => void) | undefinedOptional | Receives action key and the original Row object. Use a stable row identifier for routing or application actions; no network request occurs automatically. |
SortChanged | ((key: Extract<keyof Row, string>, direction: "Ascending" | "Descending") => void) | undefinedOptional | Raised after a sortable heading changes Key/Direction. Sorting also sets Page to 1, without a separate PageChanged callback. Read getState() to mirror the complete state. |
PageChanged | ((page: number) => void) | undefinedOptional | Raised after a Previous/Next action with the one-based page. Programmatic updates and automatic clamping do not emit this callback. |
Instance methods & properties
4| Name | Signature / type | Usage |
|---|---|---|
element | HTMLDivElement | Root DOM element owned by the component. Mount into a real host before using focus or validation. |
update | (patch: Partial<TableOptions<Row>>) => void | Shallow-merge an options patch into the current configuration. Arrays/adornment objects replace their previous value. User-change callbacks are not emitted. Call before destroy; updates afterward throw. |
getState | () => { Page: number; SortKey: Extract<keyof Row, string> | undefined; SortDirection: "Ascending" | "Descending"; } | Read current Page, SortKey and SortDirection. It includes page clamping after updates and sorting. It does not include or copy rows. |
destroy | () => void | Remove owned DOM and listeners. Destroy child component instances before their layout. Safe to call repeatedly; do not use other methods afterward. |
Related data types
Expand a type for its exact fields and allowed values. Pass objects and arrays directly in Web code.
TableOptions
Current local TypeScript declaration. Use the component-specific options and callbacks shown above.
interface TableOptions<Row extends object> {
Columns: TableColumn<Row>[]; Rows: Row[]; Caption: string; RowKey?: Extract<keyof Row, string>;
Actions?: TableAction<Row>[]; Loading?: boolean; EmptyMessage?: string;
PageSize?: number; Page?: number; SortKey?: Extract<keyof Row, string>; SortDirection?: 'Ascending' | 'Descending';
Density?: 'Compact' | 'Comfortable'; Striped?: boolean; ExtendedClass?: string;
}TableColumn
Column definitions keyed to your Row type. Format returns display text only; sorting uses the unformatted value.
interface TableColumn<Row extends object> {
Key: Extract<keyof Row, string>; Header: string; Sortable?: boolean; Align?: 'Left' | 'Center' | 'Right';
Format?: (value: Row[Extract<keyof Row, string>], row: Row) => string;
}TableAction
A row action with an optional global or per-row disabled state. JavaScript predicates are Web-only; native JSON cannot carry functions.
interface TableAction<Row> { Key: string; Label: string; Disabled?: boolean | ((row: Row) => boolean); }TableEvents
Current local TypeScript declaration. Use the component-specific options and callbacks shown above.
interface TableEvents<Row> {
RowAction?: (key: string, row: Row) => void;
SortChanged?: (key: Extract<keyof Row, string>, direction: 'Ascending' | 'Descending') => void;
PageChanged?: (page: number) => void;
}Verified native contract for BluKavantUi_Community_Data → Essentials → Table. Bindings, events and layout were verified in the compiled development consumer on 2026-10-24.
Browser checks cover labels, keyboard interactions, values and cleanup. Scoped Safari VoiceOver and browser checks passed; this is not a full-library conformance certification. Test your composed application with its actual content and assistive technologies.
Purpose and use
A semantic record table with sorting, pagination, row actions and loading states.
Keyboard design guidance
Tab reaches sortable headings, row actions and paging buttons. Activate a focused button with Enter or Space.
See the support status above for review coverage and any limitations.
In your application
Provide useful labels, preserve visible focus, and test the component with your actual content. Use text alongside status colors and check contrast in each state.
Events0No events yet.
Interact with an example to see its events.