Table
@astryxdesign/core v0.7.1 · Table
Name | Email | Role | Age |
|---|---|---|---|
| Alice Johnson | alice@example.com | Engineer | 30 |
| Bob Smith | bob@example.com | Designer | 25 |
| Charlie Brown | charlie@example.com | PM | 35 |
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:
useTableSortablecycles a header through ascending, descending, and unsorted. Shift-click adds a column whenisMultiSortEnabledis set.useTableSortableStateholds the sort and returns the sorted rows.useTableSelectionadds a checkbox column and highlights selected rows.useTableSelectionStateholds the selected ids. Pass itsselectionStatetoTableSelectionToolbarto run bulk actions on the selection; the bar stays hidden until something is selected. SethasRowHighlighttofalsewhen the row background already means something else. Checked rows stayaria-selected.useTablePaginationrenders a pager under the table. Slice the rows withpaginateDatabefore passingdata.useTableColumnSettingsshows only the active column keys, and keepsisAlwaysVisiblecolumns on.useTableColumnResizelets a header edge be dragged. The smallest width is 60px.useTableFilteringputs a string or enum filter on any column whosefilternames a field.applyTableFiltersreturns the matching rows. String fields match a substring. Enum fields match exactly. This filtering stays separate from Power Search.useTableGroupedRowsturns 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.useTableTreeStatedecides which nodes are open.useTableTreeDatadraws the indent and the buttons. Child rows reuse the parent columns. The header button expands or collapses every branch, and a cycle is skipped.useTableRowExpansionplaces a detail panel under a row. The same action is on the row’s context menu.hasRowClickExpansionalso 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.useTableStickyColumnspins 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.useTableRowStatusputs a success, warning, or error mark at the start of a row. A custom color can be a named color or a plain dot.useTableRowIndexnumbers 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.
<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:
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
| Element | Description |
|---|---|
| Table | Semantic table element that groups the table sections, rows, and cells. |
| Scroll region | Outer region that scrolls horizontally, enters the keyboard order, and contains overscroll only while the columns overflow. |
| Header section | Column-heading section generated when data-driven columns are present, or supplied with TableHeader when composing the table from slots. |
| Column header cell | Cell that identifies one column and may contain sorting or bulk-selection controls. |
| Sort control | Button that wraps a sortable column label and changes that column's sort direction. |
| Sort indicator glyph | Directional symbol rendered by Icon inside a Sort control. |
| Sort priority | Number shown for a sorted column when multi-column sorting is active. |
| Selection control | CheckboxInput rendered in the header and selectable body rows by the selection plugin. |
| Body section | Section containing data rows or the current empty state; data-driven mode renders it automatically. |
| Row | Repeated TableRow that groups cells in a standard header, body, or footer row. |
| Cell | TableCell containing one value or caller-provided content in a standard body or footer row. |
| Default empty state | Compact EmptyState shown for an empty data array unless it is replaced or disabled. |
| Expansion control | Button in a leading cell that expands or collapses one expandable row. |
| Expansion glyph | Directional symbol rendered by Icon inside an Expansion control. |
| Expanded detail panel | Detail row and spanning cell rendered below an expanded row around caller-provided content. |
| Footer section | Optional summary or totals section supplied with TableFooter when composing the table from slots. |
Best practices
| Guidance | Practices |
|---|---|
| Do | Give every row a stable idKey. Selection and row identity depend on it. |
| Do | Use pixel() for short numeric columns and proportional() for text that should share the remaining width. |
| Do | Keep sort, selection, and filter state outside the table and pass the derived rows in data. |
| Don't | Sort or paginate inside renderCell. The cell only paints the row it is given. |
| Don't | Turn 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 Johnson | alice@example.com | Engineer | Platform | Active |
| Bob Smith | bob@example.com | Designer | Product | Active |
| Charlie Brown | charlie@example.com | Manager | Platform | Away |
| Diana Prince | diana@example.com | Engineer | Infra | Active |
| Eve Davis | eve@example.com | Admin | Operations | Inactive |
Table with a column visibility picker in the toolbar. Toggle columns on and off.
Table — Popover Filters
Name | Email | Role | Department |
|---|---|---|---|
| Alice | alice@example.com | Engineer | Platform |
| Bob | bob@example.com | Designer | Product |
| Charlie | charlie@example.com | Manager | Platform |
| Diana | diana@example.com | Engineer | Infrastructure |
| Eve | eve@example.com | Admin | Operations |
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 |
| Users | 12,400 | 14,200 | 15,800 | 18,100 |
| Retention | 82% | 85% | 84% | 88% |
| NPS | 42 | 45 | 48 | 51 |
| CSAT | 4.2 | 4.3 | 4.5 | 4.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 Johnson | Engineer | alice@example.com |
| Bob Smith | Designer | bob@example.com |
| Charlie Brown | PM | charlie@example.com |
| Diana Prince | Engineer | diana@example.com |
Table composed inside a card with a heading, demonstrating container bleed alignment.
Table — Inline Filters
Name | Email | Role | Department |
|---|---|---|---|
| Alice Johnson | alice@example.com | Engineer | Platform |
| Bob Smith | bob@example.com | Designer | Product |
| Charlie Brown | charlie@example.com | Manager | Platform |
| Diana Prince | diana@example.com | Engineer | Infra |
| Eve Davis | eve@example.com | Admin | Operations |
Table with inline filter controls rendered directly below each column header.
Table — Paginated Data
Name | Email | Role |
|---|---|---|
| Alice Johnson | alice@example.com | Engineer |
| Bob Smith | bob@example.com | Designer |
| Charlie Brown | charlie@example.com | Manager |
| Diana Prince | diana@example.com | Admin |
| Eve Davis | eve@example.com | Analyst |
Paginated data table navigating through a larger dataset page by page.
Table — Resizable Columns
Name | Email | Role |
|---|---|---|
| Alice Johnson | alice@example.com | Engineer |
| Bob Smith | bob@example.com | Designer |
| Charlie Brown | charlie@example.com | PM |
| Diana Prince | diana@example.com | Engineer |
| Eve Davis | eve@example.com | Analyst |
Table with draggable column resize handles. Drag the right edge of any header to resize.
Table — Rich Cell Content
Name | Email | Role | Age |
|---|---|---|---|
| Alice Johnson | alice@example.com | Engineer | 30 |
| Bob Smith | bob@example.com | Designer | 25 |
| Charlie Brown | charlie@example.com | PM | 35 |
| Diana Prince | diana@example.com | Engineer | 28 |
| Eve Davis | eve@example.com | Designer | 32 |
Table with rich cell content using Link for emails and Badge for role labels.
Table — Row Selection
Name | Email | Role | |
|---|---|---|---|
| Alice | alice@example.com | Engineer | |
| Bob | bob@example.com | Designer | |
| Charlie | charlie@example.com | Manager | |
| Diana | diana@example.com | Engineer | |
| Eve | eve@example.com | Admin |
Table with row selection checkboxes and a select-all header checkbox.
Table — Sortable Columns
| Alice | alice@example.com | Engineer | 32 |
| Bob | bob@example.com | Designer | 28 |
| Charlie | charlie@example.com | Manager | 45 |
| Diana | diana@example.com | Engineer | 37 |
| Eve | eve@example.com | Admin | 29 |
Table with sortable columns, click headers to sort ascending or descending.
Table — Striped Rows
Name | Email | Role | Age |
|---|---|---|---|
| Alice Johnson | alice@example.com | Engineer | 30 |
| Bob Smith | bob@example.com | Designer | 25 |
| Charlie Brown | charlie@example.com | PM | 35 |
| Diana Prince | diana@example.com | Engineer | 28 |
| Eve Davis | eve@example.com | Designer | 32 |
Table with alternating row colors and hover highlighting for easy scanning.
Table — Grouped rows
# | Name | Role |
|---|---|---|
| Designer (2) | ||
| 1 | Bob | Designer |
| 2 | Diego | Designer |
| Engineer (2) | ||
| 3 | Alice | Engineer |
| 4 | Carol | Engineer |
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 |
Web | Lin |
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 |
|---|---|---|---|
| 1042 | Northwind | $240 | |
Two seats, ships Friday. | |||
| 1043 | Contoso | $80 | |
| 1044 | Fabrikam | $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 |
|---|---|---|---|---|---|
| Alice | Desk | Desk | Remote | Desk | Off |
| Bob | Remote | Desk | Desk | Remote | Desk |
| Carol | Off | Remote | Desk | Desk | Remote |
Name stays on the left and Friday stays on the right while the days in between scroll.
Table — Row status
Row status | Service | Detail |
|---|---|---|
| Payments | Settled | |
| Inventory | Low stock | |
| Bounced | ||
| Notes | No signal |
The mark at the start of a row is success, warning, error, or a dot with no signal.