Offer the row-delete affordances — the row context-menu item and the bulk delete in the selection badge. Set false for an "edit cells, never rows" grid so it never shows a delete it will refuse
allowColumnReorder
boolean
true
Enable drag-and-drop column reorder
allowMultiColumnDrag
boolean
true
Enable selecting and dragging multiple columns
confirmBeforeDelete
boolean
true
Show confirmation dialog before destructive actions
Toolbar
Prop
Type
Default
Description
showToolbar
boolean
true
Show the toolbar above the grid
showSearch
boolean
true
Show the search input
showFilters
boolean
true
Show the filter button
showRowHeightControl
boolean
true
Show the row height dropdown
showRowNumbersControl
boolean
true
Show the row numbers toggle
showAddRowButton
boolean
true
Show the add-row button
Locale & Formatting
Prop
Type
Default
Description
locale
string
'en-US'
BCP 47 locale tag (e.g. 'es-CO', 'ja-JP')
language
string
—
UI language override — defaults to locale primary subtag
interface MonkeyTableColumn {
id: string; // column key (used in row data)
label?: string; // display label — defaults to id
type?: FieldType; // defaults to 'Text'
options?: FieldOptions; // type-specific options
description?: string; // header tooltip / caption text
descriptionDisplay?: 'tooltip' | 'caption'; // how description renders (default: 'tooltip')
icon?: ReactNode; // custom column header icon
render?: CellRendererFn; // custom cell renderer for this column
hidden?: boolean; // hide column but keep data accessible
editable?: boolean; // per-column read-only override
width?: number; // initial width in pixels (default: 180)
minWidth?: number; // minimum width (default: 80)
maxWidth?: number; // maximum width (default: 600)
sortable?: boolean; // can this column be sorted (default: true)
align?: 'left' | 'center' | 'right'; // cell text alignment
color?: string | CellColorFn; // column color — static string or per-cell fn
}
type CellColorFn = (
row: Record<string, Value>,
value: Value,
fieldId: string,
) => string | undefined;
Column coloring (column.color)
Three shapes, from simplest to most flexible:
Static (string) — any CSS color. Every cell in the column plus the header gets a soft tint of that color. Good for marking a non-editable column, flagging a column that needs attention, or grouping related columns visually.
Rule array (ColorRule[]) — JSON-serializable conditional formatting. Each rule is { when: ColorCondition, color: string }. Rules evaluate top-down; first match wins. Header stays default in this mode. Works in the JSON config form.
Function (CellColorFn) — (row, value, fieldId) => string | undefined. For anything the rule array can't express: palettes, numeric interpolation, cross-field math. Header stays default. Prop-API only (functions aren't JSON-serializable).
Tints always blend with color-mix(… 30%, white) so dark colors stay readable, and compose cleanly with the row-level colorBy tint and the in-search yellow highlight.
<MonkeyTable
columns={[
{ id: 'Name' },
// Static: the whole "CreatedAt" column + header reads as a read-only band.
{ id: 'CreatedAt', type: 'Date', editable: false, color: '#f1f5f9' },
// Rule array: red < 50, green ≥ 90, else untouched. Also works in JSON config.
{
id: 'Score',
type: 'Number',
color: [
{ when: { op: 'lt', value: 50 }, color: '#fee2e2' },
{ when: { op: 'gte', value: 90 }, color: '#dcfce7' },
],
},
// Function: same effect but with a mid-range yellow band, and arbitrary logic.
{
id: 'Priority',
color: (_row, value) => {
if (value === 'P0') return '#fecaca';
if (value === 'P1') return '#fed7aa';
return undefined;
},
},
]}
rows={rows}
/>
Rule operators.ColorCondition is a tagged union keyed by op:
op
value(s)
Matches when
equals / notEquals
value: unknown
strict === / !==
lt / lte / gt / gte
value: number
numeric comparison (non-numeric cells never match)
contains / notContains
value: string
case-insensitive substring on string cells
empty / notEmpty
—
null, undefined, "", or []
in / notIn
values: unknown[]
value is / isn't one of the list
Every operator accepts an optional field: string to compare against a different column's value instead of the cell's own — useful for "tint the Status cell when Owner is empty":
format (date/datetime/time), dateFormat, use24Hour
SingleSelect
Dropdown selection
options: [{ value, label, color }]
MultiSelect
Multiple selections
options: [{ value, label, color }], maxSelections
Image
Image thumbnails with URL links
maxImages, maxFileSize, displaySize
Attachment
Generic file attachments
maxFiles, maxFileSize, allowedTypes
Email
Email address with mailto link
—
URL
Clickable URL with optional label
—
Phone
Phone number with tel link
—
Color
Color swatch + hex value
format (hex/rgb/hsl)
Rating
Star/heart/circle rating
max, icon
Computed
Derived from other fields
functionName, inputFieldIds, params
Config-driven API
If you'd rather describe a whole table as one JSON blob — for example to store
a user's table layout, serve a table from a REST endpoint, or have an LLM emit
it from a sample of rows — use <MonkeyTableFromConfig>.
interface MonkeyTableConfig {
schemaVersion?: number; // reserved for future migrators
columns: MonkeyTableConfigColumn[]; // same as MonkeyTableColumn, minus render/icon
// and with color narrowed to string
rows: Array<Record<string, Value>>;
settings?: MonkeyTableConfigSettings;
}
settings is a flat bucket that mirrors the scalar/enum props documented
above — editable, height, pageSize, locale, groupBy, sortBy,
dateDisplayFormat, etc. Anything not serializable (React handlers, custom
renderers/editors, render/icon on a column, functions/constraints,
presence, conditional-coloring functions) stays as ordinary component props
on <MonkeyTableFromConfig>. Static column.color (CSS string) is allowed
in the config; the function form is prop-API-only.
resolveConfig
If you'd rather keep using <MonkeyTable> directly, import resolveConfig
to turn a config into the flat prop object it consumes: