Data Grid
A virtualized, editable spreadsheet-like data grid with sorting, filtering, grouping, cell selection, and keyboard navigation.
Installation
pnpm dlx @docyrus/cli add @docyrus/ui-data-gridnpx shadcn@latest add action-bar avatar badge button calendar card checkbox command dialog direction dropdown-menu input kbd popover select separator skeleton sortable switch textarea toggle-group tooltippnpm add sonner @tanstack/react-table @radix-ui/react-direction @types/react @tanstack/react-virtualUsage
import {
DataGrid,
DataGridFieldsMenu,
DataGridFilterMenu,
DataGridGroupMenu,
DataGridKeyboardShortcuts,
DataGridRowHeightMenu,
DataGridSortMenu,
DataGridViewMenu,
getDataGridSelectColumn,
useDataGrid
} from '@docyrus/ui/components/data-grid';
import type { ColumnDef, DataGridAction } from '@docyrus/ui/components/data-grid';
const columns: ColumnDef<Person>[] = [
getDataGridSelectColumn<Person>(),
{
accessorKey: 'name',
header: 'Name',
size: 180,
meta: { label: 'Name', cell: { variant: 'short-text' } }
},
{
accessorKey: 'email',
header: 'Email',
size: 220,
meta: { label: 'Email', cell: { variant: 'email' } }
},
{
accessorKey: 'status',
header: 'Status',
size: 130,
meta: {
label: 'Status',
cell: {
variant: 'status',
options: [
{ label: 'Active', value: 'active', color: '#22c55e' },
{ label: 'Inactive', value: 'inactive', color: '#ef4444' }
]
}
}
}
];
function MyGrid() {
const [data, setData] = useState(initialData);
const { table, ...gridProps } = useDataGrid({
data,
columns,
enableSearch: true,
enableGrouping: true,
onDataChange: setData,
onRowAdd: () => {
setData(prev => [...prev, emptyRow]);
return null;
},
onRowsDelete: (rows, indices) => {
setData(prev => prev.filter((_, i) => !indices.includes(i)));
}
});
return (
<div>
<div className="mb-3 flex items-center gap-2">
<DataGridFilterMenu table={table} />
<DataGridSortMenu table={table} />
<DataGridGroupMenu table={table} />
<DataGridRowHeightMenu table={table} />
<DataGridFieldsMenu table={table} />
<DataGridViewMenu table={table} storageKey="my-grid" />
</div>
<DataGridKeyboardShortcuts enableSearch />
<DataGrid table={table} {...gridProps} height={500} />
</div>
);
}Toolbar Menus
The grid provides standalone toolbar menu components. Destructure table from useDataGrid and pass it to each menu:
| Component | Description |
|---|---|
DataGridFilterMenu | Column-based filter menu (integrates with DataTableFilter) |
DataGridSortMenu | Multi-column sort configuration |
DataGridGroupMenu | Group rows by a single column |
DataGridRowHeightMenu | Row height selector (short, medium, tall, extra-tall) |
DataGridFieldsMenu | Toggle column / card-body field visibility with searchable checklist + show-all / hide-all shortcuts |
DataGridViewMenu | Column visibility, order, pinning, and saved views |
DataGridAdvancedFilter | Draft editor for an AND/OR filter group — OR, nesting and the full operator vocabulary, ANDed with the filter chips |
DataGridKeyboardShortcuts | Keyboard shortcut reference dialog (press / to open) |
All menu components accept table: Table<TData> and an optional disabled?: boolean prop.
Action Column
Use getDataGridActionsColumn to create a per-row action column. It sets sensible defaults (header: () => null, non-hideable, non-resizable, non-sortable) and auto-calculates column width from the number of action buttons.
import { getDataGridActionsColumn } from '@docyrus/ui/components/data-grid';
const actionColumn = getDataGridActionsColumn<Person>({
cell: ({ row }) => (
<div className="flex items-center gap-0.5">
<Button variant="ghost" size="icon" className="size-7" onClick={() => onExpand(row.original)}>
<Expand className="size-4" />
</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="size-7">
<MoreHorizontal className="size-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => onEdit(row.original)}>
<Pencil className="size-4" /> Edit
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive" onClick={() => onDelete(row.original)}>
<Trash2 className="size-4" /> Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
)
});
const columns = [
getDataGridSelectColumn<Person>(),
actionColumn,
...dataColumns
];By default, visibleOnHover is enabled — action buttons are hidden and fade in on row hover using CSS @media (hover: hover). On touch screens the buttons are always visible. To keep buttons always visible on all devices, set visibleOnHover: false.
const actionColumn = getDataGridActionsColumn<Person>({
visibleOnHover: false,
actionCount: 1,
cell: ({ row }) => (
<Button variant="ghost" size="icon" className="size-7">
<MoreHorizontal className="size-4" />
</Button>
)
});Bulk Actions
Show action buttons in a floating bar when rows are selected. The bar appears at the bottom of the grid with a count of selected rows and a dismiss button that clears the selection.
const actions: DataGridAction<Person>[] = [
{
label: 'Export',
icon: <Download className="size-3.5" />,
onAction: (rows) => exportToCsv(rows)
},
{
label: 'Delete',
icon: <Trash2 className="size-3.5" />,
variant: 'destructive',
onAction: (rows) => deleteRows(rows)
}
];
<DataGrid table={table} {...gridProps} actions={actions} />Change Tracking
Enable batch editing with enableChangeTracking. Edits are tracked in-memory and displayed with amber highlights. A floating action bar shows pending changes with Cancel/Save buttons.
import type { RowChange } from '@docyrus/ui/components/data-grid';
const { table, ...gridProps } = useDataGrid({
data,
columns,
enableChangeTracking: true,
onDataChange: setData,
onChangesSave: async (changes: RowChange[], data) => {
await api.batchUpdate(changes);
},
onChangesDiscard: () => {
// Optional: called when user clicks Cancel
},
getRowLabel: (row) => row.name
});Changed cells are highlighted with an amber background and left border. The floating action bar shows the count of modified rows and a popover with field-level change details (old value → new value). Editing a cell back to its original value automatically removes the highlight.
Skeleton
Use the skeleton components to show a loading placeholder while data is fetching.
import {
DataGridSkeleton,
DataGridSkeletonToolbar,
DataGridSkeletonGrid
} from '@docyrus/ui/components/data-grid';
<DataGridSkeleton>
<DataGridSkeletonToolbar actionCount={4} align="end" />
<DataGridSkeletonGrid />
</DataGridSkeleton>Views
Use DataGridViewSelect and DataGridViewEditor to let users switch between saved views and create or edit custom ones. Views control column visibility, order, pinning, and sorting.
import { applyViewToTable, type SavedDataGridView } from '@docyrus/ui/components/data-grid';
import { DataGridViewSelect } from '@docyrus/ui/components/data-grid-view-select';
import { DataGridViewEditor } from '@docyrus/ui/components/data-grid-view-select';
const [views, setViews] = useState<SavedDataGridView[]>(initialViews);
const [activeViewId, setActiveViewId] = useState('view-all');
const [editorOpen, setEditorOpen] = useState(false);
const [editingView, setEditingView] = useState<SavedDataGridView | undefined>();
<DataGridViewSelect
table={table}
variant="horizontal-tabs"
views={views}
activeViewId={activeViewId}
onViewChange={(view) => setActiveViewId(view.id)} />
<DataGridViewEditor
table={table}
open={editorOpen}
onOpenChange={setEditorOpen}
value={editingView}
onSave={(view) => {
setViews(prev => {
const idx = prev.findIndex(v => v.id === view.id);
return idx >= 0
? prev.map(v => v.id === view.id ? view : v)
: [...prev, view];
});
setActiveViewId(view.id);
applyViewToTable(table, view);
}}
onDelete={(viewId) => setViews(prev => prev.filter(v => v.id !== viewId))}
showDelete={editingView !== undefined && views.length > 1} />DataGridViewSelect
| Prop | Type | Default | Description |
|---|---|---|---|
table | Table<TData> | — | TanStack table instance |
variant | 'dropdown' | 'horizontal-tabs' | 'vertical-tabs' | 'dropdown' | Display variant |
views | SavedDataGridView[] | — | Available views |
activeViewId | string | — | Currently active view ID |
onViewChange | (view: SavedDataGridView) => void | — | Called when user selects a view |
DataGridViewEditor
| Prop | Type | Default | Description |
|---|---|---|---|
table | Table<TData> | — | TanStack table instance |
open | boolean | — | Whether the editor is open |
onOpenChange | (open: boolean) => void | — | Called when open state changes |
value | SavedDataGridView | undefined | — | View to edit (undefined for new) |
onSave | (view: SavedDataGridView) => void | — | Called when view is saved |
onDelete | (viewId: string) => void | — | Called when view is deleted |
showDelete | boolean | false | Show delete button |
SavedDataGridView
| Field | Type | Description |
|---|---|---|
id | string | Unique view identifier |
name | string | Display name |
description | string | Optional description |
columnVisibility | Record<string, boolean> | Column visibility map |
columnOrder | string[] | Column order array |
columnPinning | { left: string[], right: string[] } | Pinned columns |
sorting | SortingState | Optional sorting configuration |
Color Rules
Conditionally highlight rows or individual cells based on data values using JSONata expressions. Row rules apply a background color to the entire row; cell rules target a specific column. Rules are evaluated in order — the first matching rule wins.
import type {
DataGridRowColorRule,
DataGridCellColorRule
} from '@docyrus/ui/components/data-grid';
const rowColorRules: DataGridRowColorRule[] = [
{ formula: 'status = "Cancelled"', color: 'red-50' },
{ formula: 'total > 10000', color: 'green-50' }
];
const cellColorRules: DataGridCellColorRule[] = [
{ column: 'priority', formula: 'priority = "Urgent"', color: 'red-100' },
{ column: 'total', formula: 'total > 5000', color: 'emerald-100' }
];
const { table, ...gridProps } = useDataGrid({
data,
columns,
rowColorRules,
cellColorRules
});The color field accepts Tailwind color names (e.g. red-50, emerald-100) or raw hex values (e.g. #fef2f2). Formulas are standard JSONata expressions evaluated against each row's data object.
Color rules have lower visual priority than interactive states — selected cells, search matches, change-tracked cells, and cut cells will override color rule backgrounds.
Chart Cells
Render mini sparklines or bar charts inside cells with an optional expand popover for detailed visualizations. The cell value should be an array of numbers or data point objects.
const columns: ColumnDef<Product>[] = [
{
accessorKey: 'trend',
header: 'Revenue Trend',
size: 160,
meta: {
cell: {
variant: 'chart',
chartType: 'sparkline',
color: '#10b981',
expandedCellContent: (rowData) => {
const row = rowData as Product;
return (
<div className="space-y-2">
<h4 className="font-medium">{row.name} — Detailed Trend</h4>
{/* Full chart, stats, grid, etc. */}
</div>
);
}
}
}
},
{
accessorKey: 'weeklyUnits',
header: 'Weekly Units',
size: 140,
meta: {
cell: {
variant: 'chart',
chartType: 'bar',
dataKey: 'units',
color: '#8b5cf6'
}
}
}
];The expand icon appears on hover when expandedCellContent is provided, opening a popover with user-defined content. The expandedCellContent function receives the full row data object (row.original), allowing dynamic rendering based on any field.
| Option | Type | Default | Description |
|---|---|---|---|
chartType | 'sparkline' | 'bar' | 'sparkline' | Line chart or mini bar chart |
dataKey | string | 'value' | Key to read from each data point object |
color | string | Theme primary | Stroke (sparkline) or fill (bar) color |
expandedCellContent | (rowData: unknown) => ReactNode | — | Render function for the expanded popover content |
DataGridRowColorRule
| Field | Type | Description |
|---|---|---|
formula | string | JSONata expression evaluated against row data. Row is highlighted when the expression returns a truthy value. |
color | string | Tailwind color name (e.g. red-50) or hex value (e.g. #fef2f2) |
DataGridCellColorRule
| Field | Type | Description |
|---|---|---|
column | string | Column ID (accessorKey) to apply the color to |
formula | string | JSONata expression evaluated against row data. Cell is highlighted when the expression returns a truthy value. |
color | string | Tailwind color name (e.g. amber-100) or hex value (e.g. #fef3c7) |
Features
- Virtualized rendering — Only visible rows are rendered for optimal performance
- Cell editing — Click to select, double-click or type to edit
- Keyboard navigation — Arrow keys, Tab, Enter, Escape, Home, End, Page Up/Down
- Cell selection — Click + Shift/Ctrl for multi-cell range selection
- Copy / Cut / Paste — Ctrl+C, Ctrl+X, Ctrl+V with clipboard support
- Search — Ctrl+F to open in-grid search bar
- Context menu — Right-click for cell actions
- Row selection — Select column with checkboxes for bulk operations
- Row height — Built-in row height menu (short, medium, tall, extra-tall)
- Sorting — Column header sort menu
- Filtering — Column header filter menu
- Grouping — Group rows by column values
- Paging — Optional standard paging footer with page-size selector
- RTL support — Full right-to-left layout
- Add / Delete rows — Footer add row button, bulk delete via action bar
- Change tracking — Batch edit workflow with amber highlights, cancel/save action bar
- 30 cell variants — Comprehensive cell types for any data
Paging
The grid supports two row layouts, controlled by the pagingMode option on useDataGrid (and forwarded through gridProps):
virtual-scroll(default) — every loaded row is rendered in a single virtualized viewport. No footer. Best for grids that load all rows at once or lazily via infinite scroll.standard— rows are paginated client-side and a paging footer (<DataGridPaginationFooter>) is shown beneath the grid with first/prev/next/last buttons, the currentpage / totalindicator, and a page-size selector.
Page-size choices come from DATA_GRID_PAGE_SIZE_OPTIONS ([25, 50, 100, 200, 250, 500]); the default is DATA_GRID_DEFAULT_PAGE_SIZE (50).
import {
DataGrid,
useDataGrid
} from '@docyrus/ui/components/data-grid';
const { table, ...gridProps } = useDataGrid<Task>({
data,
columns,
pagingMode: 'standard',
pageSize: 50
});
// Spread `gridProps` — `pagingMode` flows through automatically.
return <DataGrid table={table} {...gridProps} height="auto" />;When paired with DataGridViewSelect, saved views own the paging configuration via their Paging section (toggle the footer, pick the mode, choose the page size). The Docyrus-aware useDocyrusDataGrid hook reads those view settings and forwards them to useDataGrid so the footer follows the active view automatically.
API Reference
useDataGrid
The main hook that manages all grid state. Returns an object to spread onto <DataGrid>.
| Prop | Type | Default | Description |
|---|---|---|---|
data | Array<TData> | — | Row data array |
columns | Array<ColumnDef<TData>> | — | Column definitions (TanStack Table) |
onDataChange | (data: Array<TData>) => void | — | Called when cell values change |
onRowAdd | (event?) => Partial<CellPosition> | Promise<...> | null | — | Called when "Add row" is clicked. Returning null appends at end. |
onRowsAdd | (count: number) => void | Promise<void> | — | Called when pasting requires new rows |
onRowsDelete | (rows: Array<TData>, indices: Array<number>) => void | Promise<void> | — | Called on row deletion (bulk or single) |
onPaste | (updates: Array<CellUpdate>) => void | Promise<void> | — | Custom paste handler |
onFilesUpload | (params) => Promise<Array<FileCellData>> | — | File upload handler for file/image cells |
onFilesDelete | (params) => void | Promise<void> | — | File deletion handler |
rowHeight | RowHeightValue | 'short' | Initial row height (read once at mount) |
onRowHeightChange | (height: RowHeightValue) => void | — | Row height change callback |
overscan | number | 4 | Virtual scroll overscan rows |
measureRows | boolean | false | Measure variable row heights; keep off for uniform rows to avoid layout thrash |
dir | 'ltr' | 'rtl' | — | Text direction |
autoFocus | boolean | Partial<CellPosition> | — | Auto-focus grid or specific cell on mount |
enableSingleCellSelection | boolean | false | Allow single cell click selection |
enableColumnSelection | boolean | false | Allow full column selection via header |
enableSearch | boolean | false | Enable Ctrl+F search bar |
enablePaste | boolean | false | Enable clipboard paste |
enableGrouping | boolean | true | Enable column grouping |
readOnly | boolean | — | Disable all editing |
enableChangeTracking | boolean | false | Track cell edits and show amber highlights with a save/cancel action bar |
onChangesSave | (changes: Array<RowChange>, data: Array<TData>) => void | Promise<void> | — | Called when user clicks Save with all pending changes and current data |
onChangesDiscard | () => void | — | Called when user clicks Cancel (data is automatically reverted) |
getRowLabel | (row: TData, rowIndex: number) => string | — | Custom row label for the changes popover (defaults to Row {index + 1}) |
rowColorRules | Array<DataGridRowColorRule> | — | Conditional row background color rules using JSONata formulas |
cellColorRules | Array<DataGridCellColorRule> | — | Conditional cell background color rules using JSONata formulas |
initialState | TableState (TanStack) | — | Pass-through initial state (sorting, columnVisibility, pinning, etc.) |
formatDate | (value: unknown) => string | — | Custom date formatter for date cells. Without a formatter, raw value is displayed. |
formatDateTime | (value: unknown) => string | — | Custom datetime formatter for datetime cells. Without a formatter, raw value is displayed. |
formatNumber | (value: unknown, opts?: { variant?: 'number' | 'currency' | 'percent'; currency?: string; decimalPrecision?: number; thousandSeparator?: string }) => string | — | Tenant-aware numeric formatter for number / currency / percent cells (and their gallery card rendering). Adapters should forward decimalPrecision / thousandSeparator so per-column overrides (e.g. field-autonumber) take effect; without a formatter, the built-in fallback honors the same opts. |
pagingMode | 'standard' | 'virtual-scroll' | — | When 'standard', the returned gridProps.pagingMode makes <DataGrid> render the paging footer. When unset or 'virtual-scroll', all rows render in a single virtualized viewport. |
pageSize | number | 50 | Initial page size used by TanStack pagination when pagingMode === 'standard'. |
DataGrid
The rendered grid component. Accepts the return value of useDataGrid plus visual props.
| Prop | Type | Default | Description |
|---|---|---|---|
...useDataGrid() | ReturnType<typeof useDataGrid> | — | Spread the hook's return value |
dir | 'ltr' | 'rtl' | 'ltr' | Layout direction |
height | number | 600 | Grid height in pixels |
stretchColumns | boolean | false | Stretch columns to fill available width |
addRowLabel | string | 'Add row' | Label for the add row button |
actions | Array<DataGridAction<TData>> | — | Bulk action buttons for selected rows |
pagingMode | 'standard' | 'virtual-scroll' | — | Renders the paging footer when 'standard'. Inherited from gridProps; pass explicitly to override. |
DataGridAdvancedFilter
A popover-hosted QueryBuilderDocyrus for the one query the chip bar cannot express: status = Active OR owner = me. The chip bar holds exactly one rule per column, all ANDed, with no combinator control — this is the surface for OR, nesting and the full operator vocabulary, without having to save a view.
It is a draft editor: nothing is emitted until Apply, and Apply prunes the group first (a rule with no field yet, or a between holding an empty string, is a hard error on the items endpoint; a freshly added empty group silently returns zero rows). Limits are 10 rules and 2 levels of nesting.
| Prop | Type | Default | Description |
|---|---|---|---|
table | Table<TData> | — | The TanStack table instance. Columns are read from it to build the field list. |
group | RuleGroupType | undefined | — | The group currently applied, or undefined when none is. |
onChange | (group: RuleGroupType | undefined) => void | — | Called on Apply with the pruned group, or undefined when the group is cleared. |
disabled | boolean | false | Disable the trigger. |
className | string | — | Extra className for the trigger. |
useDocyrusDataGrid mounts this automatically as part of enableFilterMenu and stores the group under a reserved columnFilters entry — see Advanced AND/OR filtering.
DataGridPaginationFooter
The standalone paging footer rendered at the bottom of <DataGrid> when pagingMode === 'standard'. Exposed as a re-export so consumers building bespoke grid wrappers can position it themselves.
| Prop | Type | Default | Description |
|---|---|---|---|
table | Table<TData> | — | TanStack Table instance from useDataGrid |
pageSizeOptions | ReadonlyArray<number> | DATA_GRID_PAGE_SIZE_OPTIONS ([25, 50, 100, 200, 250, 500]) | Page-size choices in the footer's selector |
DataGridSkeleton
Container for the loading skeleton.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes |
DataGridSkeletonToolbar
Toolbar skeleton with placeholder action buttons.
| Prop | Type | Default | Description |
|---|---|---|---|
align | 'start' | 'center' | 'end' | 'end' | Toolbar alignment |
actionCount | number | 4 | Number of placeholder action buttons |
DataGridSkeletonGrid
Grid body skeleton placeholder.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes |
getDataGridSelectColumn
Returns a column definition (id: 'select') that renders a row selection checkbox column. The header shows a "select all" checkbox with indeterminate state. Each cell shows a checkbox that supports Shift+Click for range selection via tableMeta.onRowSelect.
const selectColumn = getDataGridSelectColumn<Person>({
size: 44,
enableRowMarkers: true
});
const columns = [selectColumn, ...yourColumns];| Option | Type | Default | Description |
|---|---|---|---|
size | number | 40 | Column width in pixels |
enableRowMarkers | boolean | false | Show row numbers when checkbox is unchecked. Numbers appear on hover and disappear when the row is checked. |
readOnly | boolean | false | Render as read-only row numbers without checkboxes |
hitboxSize | 'default' | 'sm' | 'lg' | 'default' | Clickable area padding around the checkbox |
debug | boolean | false | Show a red dashed border around the clickable hitbox area (development only) |
enableHiding | boolean | false | Whether the column can be hidden via view menu |
enableResizing | boolean | false | Whether the column width can be resized |
enableSorting | boolean | false | Whether the column is sortable |
Any additional ColumnDef props (except id, header, cell) are passed through to the returned column definition.
getDataGridActionsColumn
Returns a column definition (id: 'actions') for per-row action buttons. Sets header: () => null so the cell content renders directly without the standard cell wrapper. Column width is auto-calculated from actionCount when size is not provided.
const actionColumn = getDataGridActionsColumn<Person>({
cell: ({ row }) => (
<Button variant="ghost" size="icon" className="size-7">
<MoreHorizontal className="size-4" />
</Button>
)
});
const columns = [getDataGridSelectColumn<Person>(), actionColumn, ...yourColumns];| Option | Type | Default | Description |
|---|---|---|---|
actionCount | number | 2 | Number of inline action buttons. Used to auto-calculate column width when size is not provided. |
visibleOnHover | boolean | true | Hide cell content until row hover on non-touch screens. Uses CSS @media (hover: hover) with transition-opacity. |
size | number | auto | Column width in pixels. If omitted, calculated as actionCount × 28 + (actionCount − 1) × 2 + 12. |
enableHiding | boolean | false | Whether the column can be hidden via view menu |
enableResizing | boolean | false | Whether the column width can be resized |
enableSorting | boolean | false | Whether the column is sortable |
The cell prop must be provided by the user. Any additional ColumnDef props (except id, header, meta) are passed through.
Type Reference
ColumnDef
Re-exported from @tanstack/react-table. Extended with meta fields for cell variant configuration and display behavior.
{
accessorKey: string;
header: string | (() => ReactNode);
size?: number;
meta?: {
label?: string;
group?: string;
cell?: CellOpts;
visibleOnHover?: boolean;
format?: (value: TValue, row: TData) => string;
};
}| Meta Field | Type | Description |
|---|---|---|
label | string | Display name used in menus, change tracking popover, and filter/sort/group UIs |
group | string | Column grouping category |
cell | CellOpts | Cell variant and its configuration |
visibleOnHover | boolean | Hide cell content until row hover on non-touch screens |
format | (value: TValue, row: TData) => string | Custom formatter for cell display and export |
CellOpts
A discriminated union defining the cell variant and its configuration. Set via meta.cell on column definitions.
| Variant | Additional Props | Data Type | Description |
|---|---|---|---|
short-text | — | string | Single-line text input |
long-text | — | string | Multi-line text with expand |
email | — | string | Email with mailto link |
phone | — | string | Phone number with tel link |
number | min?, max?, step?, decimalPrecision?, thousandSeparator? | number | Numeric input with constraints. Pass decimalPrecision: 0 + thousandSeparator: '' to render identifier-like values (e.g. autonumber: 394 instead of 394.00). useDocyrusFieldComponent applies these defaults for field-autonumber automatically. |
currency | currency?, min?, max?, step?, decimalPrecision?, thousandSeparator? | number | Formatted currency value. Precision/grouping overrides override the locale defaults. |
percent | min?, max?, step?, decimalPrecision?, thousandSeparator? | number | Percentage display (0-1 range). |
url | — | string | Clickable URL link |
checkbox | — | boolean | Boolean checkbox |
switch | — | boolean | Boolean toggle switch |
select | options: CellSelectOption[], display? | string | Single-select dropdown. display: 'text' renders as plain text instead of badge |
status | options: CellSelectOption[], display? | string | Color-coded status. display: 'text' renders as plain text instead of badge |
enum | appSlug, dataSourceSlug, fieldSlug, options?, display? | string | Backend-driven enum. display: 'text' renders as plain text instead of badge |
user | options: CellUserOption[] | string | User avatar + name select |
multi-select | options: CellSelectOption[] | string | Multi-value select with badges |
tag-select | options: CellSelectOption[] | string | Colored tag chips |
date | — | string | Date picker (YYYY-MM-DD) |
datetime | — | string | Date + time picker (ISO 8601) |
time | — | string | Time-only picker (HH:mm) |
duration | — | string | Duration display (HH:mm:ss) |
date-range | — | string | Date range (start,end) |
color | — | string | Color swatch + hex picker |
icon | — | string | Icon name selector |
currency-code | — | string | ISO currency code (USD, EUR, etc.) |
file | maxFileSize?, maxFiles?, accept?, multiple? | FileCellData[] | File upload cell |
image | maxFileSize?, accept? | string | Image preview + upload |
relation | dataSourceId, displayField? | string | Related record lookup (requires Docyrus) |
rating | max? | number | Star rating (default max: 5) |
user-multi-select | options: CellUserOption[] | string | Multi-user select with avatars |
chart | chartType?, dataKey?, color?, expandedCellContent? | number[] or object[] | Mini sparkline or bar chart (read-only) |
CellSelectOption
Option definition for select, status, multi-select, and tag-select variants.
| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Display label |
value | string | Yes | Internal value |
icon | FC<SVGProps> | No | Custom icon component |
iconStr | string | No | Icon name string |
color | string | No | Badge/tag color (hex) |
count | number | No | Faceted count |
CellUserOption
Extends CellSelectOption with user-specific fields.
| Field | Type | Required | Description |
|---|---|---|---|
...CellSelectOption | — | — | All select option fields |
avatarUrl | string | No | User avatar image URL |
initials | string | No | Fallback initials (e.g. "AJ") |
DataGridAction
Action button definition for the bulk action bar (shown when rows are selected).
| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Action button label |
icon | ReactNode | No | Action icon |
variant | 'default' | 'destructive' | No | Button variant |
onAction | (selectedRows: Array<TData>) => void | Yes | Action callback with selected rows |
CellChange
Represents a single cell's change within a row.
| Field | Type | Description |
|---|---|---|
columnId | string | Column ID of the changed cell |
originalValue | unknown | Value before editing |
newValue | unknown | Current edited value |
RowChange
Represents all changes in a single row. Passed to onChangesSave as an array.
| Field | Type | Description |
|---|---|---|
rowId | string | Row identifier |
rowIndex | number | Row index in the data array |
changes | Map<string, CellChange> | Map of column ID → cell change |
RowHeightValue
type RowHeightValue = 'short' | 'medium' | 'tall' | 'extra-tall';CellUpdate
Used in paste and data update operations.
| Field | Type | Description |
|---|---|---|
rowIndex | number | Target row index |
columnId | string | Target column ID |
value | unknown | New cell value |
CellPosition
| Field | Type | Description |
|---|---|---|
rowIndex | number | Row index |
columnId | string | Column ID |
FileCellData
Data shape for files in file and image cell variants.
| Field | Type | Description |
|---|---|---|
id | string | Unique file ID |
name | string | File name |
size | number | File size in bytes |
type | string | MIME type |
url | string? | Download/preview URL |
Direction
type Direction = 'ltr' | 'rtl';Keyboard Shortcuts
| Shortcut | Action |
|---|---|
Arrow Keys | Navigate between cells |
Tab / Shift+Tab | Move to next/previous cell |
Enter | Start editing / Confirm edit |
Escape | Cancel edit / Clear selection |
Ctrl+F | Open search |
Ctrl+C | Copy selected cells |
Ctrl+X | Cut selected cells |
Ctrl+V | Paste from clipboard |
Ctrl+A | Select all cells |
Delete / Backspace | Clear selected cells |
Home / End | Jump to first/last cell in row |
Ctrl+Home / Ctrl+End | Jump to first/last cell in grid |
Page Up / Page Down | Scroll up/down by page |
Shift+Click | Range selection |
Ctrl+Click | Toggle cell in selection |
Data Gallery
A standalone, virtualized card gallery view for record lists. Toolbar-driven card design (variant, cover style, density, field bindings) plus full TanStack Table integration for sorting, filtering, grouping, and saved views.
Data Grid View Select
A view selector with integrated view editor for DataGrid. Supports dropdown, horizontal-tabs, and vertical-tabs variants with full CRUD operations on saved views.