Skip to content

Display columns

A display column renders UI that isn’t a value pulled from a row — checkboxes, expand chevrons, action buttons, row numbers. shadstack-table ships a built-in set, all of them named with the sst-row- prefix, and turns each one on automatically when you enable the corresponding feature in SST_TableOptions.

Column IDEnabled byWhat it renders
sst-row-selectenableRowSelection: truePer-row checkbox + select-all checkbox in the header.
sst-row-expandenableExpanding: true (or detail panels)Expand chevron + optional expand-all in the header.
sst-row-actionsenableRowActions: trueRow-level kebab menu (populated by renderRowActionMenuItems).
sst-row-dragenableRowDragging: trueDrag handle for row reorder.
sst-row-numbersenableRowNumbers: true1-indexed row counter.
sst-row-pinenableRowPinning: truePin / unpin button per row.
sst-row-spacer(internal)Spacer column used by virtualization in some layout modes.

You don’t typically declare these yourself — the table inserts them when the feature is on. You can reference them by ID in state.columnOrder / state.columnPinning to control where they appear:

useShadStackTable({
columns,
data,
enableRowSelection: true,
enableRowActions: true,
initialState: {
columnPinning: {
left: ['sst-row-select'],
right: ['sst-row-actions'],
},
},
});

For UI that isn’t covered by the built-ins, write your own. The pattern is: a column with an id (no accessorKey / accessorFn) and a Cell renderer that returns the UI for each row:

import { Button } from '@/components/ui/button';
import { Trash2 } from 'lucide-react';
const columns: SST_ColumnDef<Person>[] = [
// ...data columns
{
id: 'delete',
header: '',
size: 48,
enableSorting: false,
enableColumnFilter: false,
Cell: ({ row, table }) => (
<Button
variant="ghost"
size="icon"
onClick={() => onDelete(row.original.id)}
aria-label="Delete row"
>
<Trash2 className="size-4" />
</Button>
),
},
];

Display columns are non-sortable and non-filterable by default — there’s no row value to compare. Set enableSorting: false / enableColumnFilter: false explicitly if you want to silence the column-actions menu entries for them.

The default order is: data columns first, then display columns at the right edge in the order they were enabled. Override with state.columnOrder / initialState.columnOrder — list every column ID (data and display) in the order you want.