Table options
SST_TableOptions<TData> is the single configuration object passed to useShadStackTable. Everything the table does — what data it renders, which features are on, how state is held, what slots get overridden — flows through it.
import { ShadStackTable, useShadStackTable, type SST_ColumnDef, type SST_TableOptions,} from 'shadstack-table';
const options: SST_TableOptions<Person> = { columns, data, // ...everything else is optional, documented below};
const table = useShadStackTable(options);return <ShadStackTable table={table} />;Required
Section titled “Required”| Option | Type | Description |
|---|---|---|
columns | SST_ColumnDef<TData>[] | Column definitions. See SST_ColumnDef for the full shape. Memoize this with useMemo — re-creating the array re-renders the table. |
data | TData[] | Row data. Same array identity stability rule as columns — keep it referentially stable when nothing has changed. |
Both are typed against the same TData generic, so accessorKey on a column is narrowed to the keys of your row type.
Defaults & initial state
Section titled “Defaults & initial state”| Option | Type | Description |
|---|---|---|
defaultColumn | Partial<SST_ColumnDef<TData>> | Default props merged into every column. Set things like size, enableSorting, enableColumnFilter once. |
initialState | Partial<SST_TableState<TData>> | Starting state — columnVisibility, columnOrder, columnPinning, sorting, pagination.pageSize, density, etc. |
state | Partial<SST_TableState<TData>> | Controlled state. Pair with the corresponding on*Change handlers to manage state outside the table. |
Feature toggles
Section titled “Feature toggles”Every major feature has an enable* boolean. They default sensibly — start with what you need and turn things off as you scope down. Selected highlights:
| Group | Options |
|---|---|
| Sorting | enableSorting, enableMultiSort, enableMultiRemove, enableSortingRemoval |
| Filtering | enableColumnFilters, enableGlobalFilter, enableColumnFilterModes, enableGlobalFilterModes, enableGlobalFilterRankedResults, enableFacetedValues, enableFilterMatchHighlighting, enableFilterByColumnMenuItem, enableFilterModeMenuDividers |
| Row selection | enableRowSelection, enableSelectAll, enableMultiRowSelection, enableBatchRowSelection |
| Pagination | enablePagination |
| Expansion | enableExpanding, enableExpandAll |
| Editing | enableEditing, enableCellActions |
| Virtualization | enableRowVirtualization, enableColumnVirtualization |
| Pinning | enableColumnPinning, enableRowPinning, enablePinning |
| Reorder & drag | enableColumnDragging, enableRowDragging, enableColumnOrdering, enableRowOrdering |
| Column resize | enableColumnResizing |
| Visibility | enableHiding, enableColumnActions |
| Toolbars | enableTopToolbar, enableBottomToolbar, enableToolbarInternalActions, enableDensityToggle, enableFullScreenToggle, enableGlobalFilterToggle |
| Layout polish | enableTableHead, enableTableFooter, enableStickyHeader, enableStickyFooter, enableRowNumbers |
| Misc | enableClickToCopy, enableRowActions, enableKeyboardShortcuts |
Most of these accept boolean or, for row-targeted features, (row: SST_Row<TData>) => boolean — handy for “selectable only when X” / “editable only when Y” rules.
State change handlers
Section titled “State change handlers”Every state slice you might want to control externally has a matching on*Change handler. Pair them with a corresponding entry in state to drive state from your own store:
const [sorting, setSorting] = useState<SST_SortingState>([]);
const table = useShadStackTable({ columns, data, state: { sorting }, onSortingChange: setSorting,});The handler signature is TanStack’s OnChangeFn<T> — it takes the next value or an updater function (prev) => next. Apply it the same way useState’s setter applies updates.
Common change handlers: onSortingChange, onColumnFiltersChange, onGlobalFilterChange, onPaginationChange, onColumnVisibilityChange, onColumnOrderChange, onColumnPinningChange, onRowSelectionChange, onExpandedChange, onDensityChange, onIsFullScreenChange.
Slot customization
Section titled “Slot customization”slotProps is the single passthrough for styling and prop-overriding every internal slot — toolbars, head cells, body cells, buttons, dialogs, etc. Each slot’s slotProps shape accepts the same props the underlying shadcn primitive does.
useShadStackTable({ columns, data, slotProps: { tablePaper: { className: 'rounded-xl' }, tableContainer: { className: 'max-h-[480px]' }, tableHeadCell: { className: 'bg-muted/40' }, },});Slots also accept callbacks of the form (props) => className | object when the override depends on the current row, column, or cell.
What className cannot reach
Section titled “What className cannot reach”Some slots receive an inline style from the library. Inline styles outrank any class, so a className setting one of these properties is accepted and silently loses:
| Property | Slots | Where it comes from |
|---|---|---|
backgroundColor | tablePaper, topToolbar, bottomToolbar, tableHeadRow, tableBodyRow, footer row | theme.baseBackgroundColor; body rows also read selectedRowBackgroundColor and pinnedRowBackgroundColor |
maxHeight | tableContainer | enableStickyHeader — clamp(350px, calc(100vh - <toolbar height>), 9999px). Full-screen uses calc(100vh - <toolbar height>) |
Head and body cells inherit their row’s background rather than setting one, so styling the row covers the cells.
Every slot merges slotProps.<slot>.style after its own, so style on the same slot wins:
slotProps: { // Hand the surface back to CSS; the class can now paint it. tablePaper: { style: { backgroundColor: 'transparent' }, className: 'glass rounded-lg' }, // Size by the parent instead of the viewport — for a table in a pane, // a modal, or a split view rather than a full page. tableContainer: { style: { maxHeight: 'none' }, className: 'min-h-0 flex-1' },}For colour specifically, theme is usually the shorter route: it is merged over the library defaults, so a partial theme stays partial and one key reaches every surface that reads it.
Input backgrounds
Section titled “Input backgrounds”Inputs the library renders — global search, column filters, cell editors — take their background from --sst-input-bg, defaulting to shadcn’s own (transparent in light, input/30 in dark). A host whose form controls paint a solid field colour sets it once:
:root { --sst-input-bg: var(--your-field-color);}That covers both colour modes and every input slot. Overriding slotProps.searchInput / slotProps.filterInput with a background class also works, but needs repeating per slot and per mode.
Renderers
Section titled “Renderers”For deep customization of a specific surface — toolbar layout, empty state, action menu, etc. — provide a render* callback in place of overriding via slotProps. The renderer is passed { table, ... } and returns a ReactNode:
renderTopToolbar(props)/renderBottomToolbar(props)renderEmptyRowsFallback(props)renderRowActions(props),renderRowActionMenuItems(props)renderCellActionMenuItems(props),renderColumnActionsMenuItems(props)renderDetailPanel(props)renderColumnFilterModeMenuItems(props),renderGlobalFilterModeMenuItems(props)
Addressing built-in menu entries
Section titled “Addressing built-in menu entries”renderColumnActionsMenuItems receives the built-in entries as
internalColumnMenuItems. Each carries a stable id from
SST_COLUMN_MENU_ITEM_IDS as its React key, so an override can target one
entry without depending on its position:
import { SST_COLUMN_MENU_ITEM_IDS } from 'shadstack-table';
renderColumnActionsMenuItems: ({ internalColumnMenuItems }) => internalColumnMenuItems.filter((item) => item.key !== SST_COLUMN_MENU_ITEM_IDS.filterByColumn);Reach for this when you’re overriding the slot anyway — to reorder entries,
relabel one, or splice your own in. To only hide an entry, use the option that
produces it (enableSorting, enableGrouping, enableColumnPinning,
enableColumnResizing, enableHiding, enableFilterByColumnMenuItem); an
override taken to hide something also freezes the entries you kept at their
current behaviour.
Other options worth knowing
Section titled “Other options worth knowing”| Option | Description |
|---|---|
localization | Override individual UI strings. See the localization guide. |
memoMode | Memoize cells / rows / the whole body for very large datasets. See memoize-components. |
layoutMode | 'semantic' (default) renders <table> semantics; 'grid' / 'grid-no-grow' uses CSS Grid for tighter layout control. |
positionToolbarAlertBanner | 'top' / 'bottom' / 'none'. Controls where the selection/filter banner appears. |
icons | Override the default lucide icon set with your own components. Keys match the SST_Default_Icons shape. |
See also
Section titled “See also”SST_ColumnDef— every column option- Data columns guide — accessor patterns
- Display columns guide — built-in selection / expand / actions columns
- Localization
- Memoize components