Skip to content

Table

@astryxdesign/core v0.7.1 · Table

Name
Email
Role
Age
Alice Johnsonalice@example.comEngineer30
Bob Smithbob@example.comDesigner25
Charlie Browncharlie@example.comPM35

Usage ​

Table renders from data and columns. Each column has a key, a header, and an optional width from proportional() or pixel(). A cell shows row[key] unless renderCell returns something else. idKey identifies a row. The default is id.

Behavior is added with plugins, composed in the plugins object:

  • useTableSortable cycles a header through ascending, descending, and unsorted. Shift-click adds a column when isMultiSortEnabled is set. useTableSortableState holds the sort and returns the sorted rows.
  • useTableSelection adds a checkbox column and highlights selected rows. useTableSelectionState holds the selected ids. Pass its selectionState to TableSelectionToolbar to run bulk actions on the selection; the bar stays hidden until something is selected. Set hasRowHighlight to false when the row background already means something else. Checked rows stay aria-selected.
  • useTablePagination renders a pager under the table. Slice the rows with paginateData before passing data.
  • useTableColumnSettings shows only the active column keys, and keeps isAlwaysVisible columns on.
  • useTableColumnResize lets a header edge be dragged. The smallest width is 60px.
  • useTableFiltering puts a string or enum filter on any column whose filter names a field. applyTableFilters returns the matching rows. String fields match a substring. Enum fields match exactly. This filtering stays separate from Power Search.
  • useTableGroupedRows turns the rows you already filtered, sorted, and sliced into sections. Pass its data, plugin, and row identity back to the table together. A collapsed section keeps its header. Replace the collapsed set instead of mutating it.
  • useTableTreeState decides which nodes are open. useTableTreeData draws the indent and the buttons. Child rows reuse the parent columns. The header button expands or collapses every branch, and a cycle is skipped.
  • useTableRowExpansion places a detail panel under a row. The same action is on the row’s context menu. hasRowClickExpansion also toggles from a click on the row, and leaves buttons, links, editable text, and an existing text selection alone. The panel lines up with the first column and is not counted as a striped row. Use the tree plugins when the children should reuse the columns.
  • useTableStickyColumns pins the contiguous run from the first column through a listed key, or from a listed key through the last column. The shadow appears only while the table overflows. An empty config pins nothing.
  • useTableRowStatus puts a success, warning, or error mark at the start of a row. A custom color can be a named color or a plain dot.
  • useTableRowIndex numbers real rows. Group headers do not take a number.

A column with no width stays at least 60px wide. A style.minWidth smaller than the sum of those floors is raised so the columns stay readable; a larger value is kept. A table that fits does not trap the scroll chain. Horizontal overscroll is contained only while the table actually overflows.

density is compact, balanced, or spacious. dividers is rows, columns, grid, or none. isStriped and hasHover are independent. An empty data array renders the localized empty message, or the empty slot.

Without data, the table is composed from TableHeader, TableBody, TableFooter, TableRow, TableHeaderCell, and TableCell.

vue
<script setup lang="ts">
import { proportional, Table } from '@astryx-vue/core/Table'

const rows = [
  { id: '1', name: 'Alice Johnson', email: 'alice@example.com' },
]
const columns = [
  { key: 'name', header: 'Name', width: proportional(1) },
  { key: 'email', header: 'Email', width: proportional(2) },
]
</script>

<template>
  <Table :data="rows" :columns="columns" has-hover />
</template>

Pass the column filter state through a getter so the table reads the latest value:

ts
const { filters, onFilterChange } = useTableFilterState()
const filterPlugin = useTableFiltering(() => ({
  filters: filters.value,
  onFilterChange,
  fields,
}))

rowCount and rowIndexStart report where the visible window sits in the full result. Setting either one numbers the data rows. When only the start is set, the total count is unknown. Group headers and detail panels are not numbered.

Anatomy

ElementDescription
TableSemantic table element that groups the table sections, rows, and cells.
Scroll regionOuter region that scrolls horizontally, enters the keyboard order, and contains overscroll only while the columns overflow.
Header sectionColumn-heading section generated when data-driven columns are present, or supplied with TableHeader when composing the table from slots.
Column header cellCell that identifies one column and may contain sorting or bulk-selection controls.
Sort controlButton that wraps a sortable column label and changes that column's sort direction.
Sort indicator glyphDirectional symbol rendered by Icon inside a Sort control.
Sort priorityNumber shown for a sorted column when multi-column sorting is active.
Selection controlCheckboxInput rendered in the header and selectable body rows by the selection plugin.
Body sectionSection containing data rows or the current empty state; data-driven mode renders it automatically.
RowRepeated TableRow that groups cells in a standard header, body, or footer row.
CellTableCell containing one value or caller-provided content in a standard body or footer row.
Default empty stateCompact EmptyState shown for an empty data array unless it is replaced or disabled.
Expansion controlButton in a leading cell that expands or collapses one expandable row.
Expansion glyphDirectional symbol rendered by Icon inside an Expansion control.
Expanded detail panelDetail row and spanning cell rendered below an expanded row around caller-provided content.
Footer sectionOptional summary or totals section supplied with TableFooter when composing the table from slots.

Best practices ​

GuidancePractices
DoGive every row a stable idKey. Selection and row identity depend on it.
DoUse pixel() for short numeric columns and proportional() for text that should share the remaining width.
DoKeep sort, selection, and filter state outside the table and pass the derived rows in data.
Don'tSort or paginate inside renderCell. The cell only paints the row it is given.
Don'tTurn on every plugin in one table. A dense grid rarely also needs filters, resize, and selection at once.

Examples ​

Table — Column Settings

Name
Email
Role
Department
Status
Alice Johnsonalice@example.comEngineerPlatformActive
Bob Smithbob@example.comDesignerProductActive
Charlie Browncharlie@example.comManagerPlatformAway
Diana Princediana@example.comEngineerInfraActive
Eve Daviseve@example.comAdminOperationsInactive

Table with a column visibility picker in the toolbar. Toggle columns on and off.

Table — Popover Filters

Name
Email
Role
Department
Alicealice@example.comEngineerPlatform
Bobbob@example.comDesignerProduct
Charliecharlie@example.comManagerPlatform
Dianadiana@example.comEngineerInfrastructure
Eveeve@example.comAdminOperations

Table with popover filter controls triggered by icons in column headers.

Table — Grid Dividers

Metric
Q1
Q2
Q3
Q4
Revenue$1.2M$1.4M$1.3M$1.8M
Users12,40014,20015,80018,100
Retention82%85%84%88%
NPS42454851
CSAT4.24.34.54.6

Compact table with grid dividers showing both row and column borders, suited for dense numeric data.

Table — In Card

Team Members

Name
Role
Email
Alice JohnsonEngineeralice@example.com
Bob SmithDesignerbob@example.com
Charlie BrownPMcharlie@example.com
Diana PrinceEngineerdiana@example.com

Table composed inside a card with a heading, demonstrating container bleed alignment.

Table — Inline Filters

Name
Email
Role
Department
Alice Johnsonalice@example.comEngineerPlatform
Bob Smithbob@example.comDesignerProduct
Charlie Browncharlie@example.comManagerPlatform
Diana Princediana@example.comEngineerInfra
Eve Daviseve@example.comAdminOperations

Table with inline filter controls rendered directly below each column header.

Table — Paginated Data

Name
Email
Role
Alice Johnsonalice@example.comEngineer
Bob Smithbob@example.comDesigner
Charlie Browncharlie@example.comManager
Diana Princediana@example.comAdmin
Eve Daviseve@example.comAnalyst

Paginated data table navigating through a larger dataset page by page.

Table — Resizable Columns

Name
Email
Role
Alice Johnsonalice@example.comEngineer
Bob Smithbob@example.comDesigner
Charlie Browncharlie@example.comPM
Diana Princediana@example.comEngineer
Eve Daviseve@example.comAnalyst

Table with draggable column resize handles. Drag the right edge of any header to resize.

Table — Rich Cell Content

Name
Email
Role
Age
Alice Johnsonalice@example.comEngineer30
Bob Smithbob@example.comDesigner25
Charlie Browncharlie@example.comPM35
Diana Princediana@example.comEngineer28
Eve Daviseve@example.comDesigner32

Table with rich cell content using Link for emails and Badge for role labels.

Table — Row Selection

Name
Email
Role
Alicealice@example.comEngineer
Bobbob@example.comDesigner
Charliecharlie@example.comManager
Dianadiana@example.comEngineer
Eveeve@example.comAdmin

Table with row selection checkboxes and a select-all header checkbox.

Table — Sortable Columns

Alicealice@example.comEngineer32
Bobbob@example.comDesigner28
Charliecharlie@example.comManager45
Dianadiana@example.comEngineer37
Eveeve@example.comAdmin29

Table with sortable columns, click headers to sort ascending or descending.

Table — Striped Rows

Name
Email
Role
Age
Alice Johnsonalice@example.comEngineer30
Bob Smithbob@example.comDesigner25
Charlie Browncharlie@example.comPM35
Diana Princediana@example.comEngineer28
Eve Daviseve@example.comDesigner32

Table with alternating row colors and hover highlighting for easy scanning.

Table — Grouped rows

#
Name
Role
Designer (2)
1BobDesigner
2DiegoDesigner
Engineer (2)
3AliceEngineer
4CarolEngineer

Rows split by role. A collapsed section keeps its header, and the row numbers skip those headers.

Table — Tree data

Name
Owner
Platform
Ada
API
Grace
Design
Noah

Child rows reuse the same columns. The header expands every branch, and a row click expands a node that has children.

Table — Row expansion

Row expansion
Order
Customer
Total
1042Northwind$240

Two seats, ships Friday.

1043Contoso$80
1044Fabrikam$560

Open the note under a row from the chevron, the row, or the context menu.

Table — Sticky columns

Name
Monday
Tuesday
Wednesday
Thursday
Friday
AliceDeskDeskRemoteDeskOff
BobRemoteDeskDeskRemoteDesk
CarolOffRemoteDeskDeskRemote

Name stays on the left and Friday stays on the right while the days in between scroll.

Table — Row status

Row status
Service
Detail
PaymentsSettled
InventoryLow stock
MailBounced
NotesNo signal

The mark at the start of a row is success, warning, error, or a dot with no signal.