Table

stable 14.2 kB
<hk-table>

The one component that has to do everything: hierarchical headers of any depth, per-column and global filtering, single or multi-column sort, client or server paging, selection, row expansion, row grouping, frozen columns, resize, reorder, column visibility, inline editing, footer aggregates, virtual scrolling, CSV export and persisted state. It renders through delegated events and a windowed body, so ten thousand rows scroll at frame rate instead of turning into a slideshow.

#grid#datatable#virtual#filter#sort

Live demo

Running in this page — interact with it.

Inputs

NameTypeDefaultDescription
valueT[][]Rows to render. With [lazy] this is the current page only.
columnsHkColumn<T>[][]Column tree. Nest children for grouped headers of any depth.
dataKeystring''Unique row field. Required for stable selection, expansion and editing.
loadingbooleanfalseShows the loading overlay and sets aria-busy.
lazybooleanfalseHands sorting, filtering and paging to the server through (lazyLoad).
totalRecordsnumber | nullnullServer-side row count. Only read when lazy.
paginatorbooleanfalseRenders the pager and slices the data client-side.
first / rowsnumber0 / 10Page offset and page size. Both two-way bindable.
rowsPerPageOptionsnumber[][10, 25, 50, 100]Page-size choices. Pass [] to hide the selector.
sortMode'single' | 'multiple''single'In multiple mode, shift-click stacks sort fields.
sortHkSortMeta[][]Active sort stack, outermost first. Two-way bindable.
filtersHkFilterState{}Per-column filter state, keyed by dotted column id.
globalFilterstring''Search term. Two-way bindable; debounced by searchDelay.
globalFilterFieldsstring[][]Fields the search looks at. Defaults to every visible leaf.
selectionMode'single' | 'multiple' | 'checkbox' | nullnullHow rows are picked. Checkbox adds a leading column with select-all.
selectionT[][]Selected rows — always an array, even in single mode. Two-way bindable.
rowExpansionbooleanfalseAdds the expander column; pair with an "expansion" template.
expandedKeysRecord<string, boolean>{}Open rows, keyed by dataKey. Two-way bindable.
groupRowsBystring''Field to group rows by. Groups render contiguously.
rowGroupMode'subheader' | 'rowspan''subheader'Collapsible group header row, or a merged cell spanning the group.
showGroupFooterbooleanfalsePer-group subtotal row using each column aggregate.
virtualScrollbooleanfalseWindows the body to the visible rows. Needs a scrollHeight.
virtualRowHeightnumber36Row height in px. Rows are pinned to it so the spacers stay exact.
scrollHeightstring''Max height of the scroll viewport, e.g. "24rem".
stickyHeaderbooleantruePins every header row, offsetting each by the ones above it.
resizableColumnsbooleanfalseDrag a header edge to resize. Switches the table to fixed layout.
reorderableColumnsbooleanfalseDrag top-level headers to reorder them.
columnTogglebooleanfalseAdds the column-visibility menu to the toolbar.
editMode'cell' | 'row' | nullnullCell edits on double-click or Enter; row mode adds Save/Cancel controls.
size'sm' | 'md' | 'lg''md'Density. Drives padding and font size off one token.
striped / gridlines / hoverbooleanfalse / true / trueChrome toggles.
showIndexbooleanfalseSerial-number column, continuous across pages.
showSearch / showExportbooleanfalseToolbar search box and CSV export button.
rowClassstring | ((row: T, i: number) => string)''Extra classes per row — threshold highlighting and the like.
keyboardNavigationbooleantrueArrow-key cell focus, Space to select, Enter to edit.
stateKeystring''Persists sort, filters, page, widths, order and visibility under this key.

Outputs

  • lazyLoadEventEmitter<HkTableLazyEvent>

    Server needs a page. Carries first, rows, sort, filters and the trigger.

  • pageChangeEventEmitter<HkPageEvent>

    Page or page size changed.

  • sortChangeEventEmitter<HkSortMeta[]>

    The sort stack after the click.

  • rowSelect / rowUnselectEventEmitter<{ row, index }>

    One row moved in or out of the selection.

  • rowExpand / rowCollapseEventEmitter<{ row, key }>

    Detail panel opened or closed.

  • editComplete / editCancelEventEmitter<HkEditEvent<T>>

    An edit was committed or abandoned. Carries value and oldValue.

  • columnResize / columnReorderEventEmitter<…>

    Column geometry changed — persist it yourself, or use stateKey.

Methods

  • reset()() => void

    Clears sort, filters, paging and every column override.

  • clearFilters()() => void

    Drops all column filters and the search term.

  • exportCsv()() => void

    Exports the filtered, sorted set — not just the visible page.

  • expandAll() / collapseAll()() => void

    Bulk row expansion.

  • refresh()() => void

    Re-runs the pipeline, or re-asks the server when lazy.

Keyboard

  • ← ↑ → ↓ Move cell focus
  • Home / End First / last column in the row
  • Space Toggle selection of the focused row
  • Enter Start editing the focused cell
  • Escape Abandon the edit and restore the old value
  • Shift + click header Add the column to the sort stack (multiple mode)

Theming

Component tokens, each falling back to a global one:

PropertyDefaultControls
--hk-table-header-bg#121214Header row background. Sticky rows inherit it.
--hk-table-row-hoverrgb(255 255 255 / 0.04)Row hover wash.
--hk-table-stripergb(255 255 255 / 0.02)Even-row tint when [striped].
--hk-table-selectedrgb(220 38 38 / 0.16)Selected-row background.
--hk-table-density1Multiplier on cell padding. [size] sets it; override for anything between.
--hk-table-cell-x0.7remHorizontal cell padding.
--hk-table-frozen-shadow8px 0 12px -10px rgb(0 0 0 / 0.85)Edge shadow that separates a frozen column from the scrolling body.
--hk-table-panel-bg#141416Background for the filter and column-toggle panels.

Accessibility

  • Renders role="grid" with aria-rowcount and aria-colcount reflecting the full set, not the page.
  • Sortable headers expose aria-sort; the sort order badge is readable text, not colour alone.
  • Grouped headers use scope="colgroup" with derived colspan/rowspan, so the reading order matches the visual one.
  • One tab stop per grid: the focused cell is the only tabbable one, arrows do the rest.
  • The loading overlay is role="status" aria-live="polite"; the grid itself sets aria-busy.

More in Data