DataGrid — dir/ui
A virtualized grid with search, sorting, filters, column menus, and optional editing.
# DataGrid
A virtualized grid with search, sorting, filters, column menus, and optional editing.
## Install
```sh
npx shadcn@4.21.0 add lr-run/dir-ui/data-grid#v0.1.2
```
[Registry item with source and dependencies](https://github.com/lr-run/dir-ui/blob/v0.1.2/registry.json)
Requires React 19, Tailwind CSS 4 and shadcn initialized with Base UI. Registry target placeholders resolve through components.json: @ui, @components, @hooks and @lib. Imports below use the conventional @/ prefix for illustration; the CLI rewrites them to your configured aliases. Shared components are installed once through registryDependencies. Theme CSS is imported by the UI modules. Existing files are never forcibly overwritten; review CLI conflicts before accepting changes. No Dir runtime is required.
Grid CSS is imported by the component. Give the grid a bounded height. Sorting and filtering emit query state; the caller supplies the resulting rows. Apply remote queries to the complete dataset before pagination.
## DataGrid, type DataGridProps, type GridSearchOptions, type GridSortOptions, type GridFilterOptions, type GridColumnSettings, type GridColumnState, type QueryField, type RecordSort, type RecordFilter, type Column, SelectColumn, renderTextEditor
```tsx
import { DataGrid, type DataGridProps, type GridSearchOptions, type GridSortOptions, type GridFilterOptions, type GridColumnSettings, type GridColumnState, type QueryField, type RecordSort, type RecordFilter, type Column, SelectColumn, renderTextEditor } from '@/components/data-grid/data-grid.tsx'
```
| Prop | Type | Default / required | Notes |
| --- | --- | --- | --- |
| columns / rows | readonly Column<R>[] / readonly R[] | Required | react-data-grid column definitions and caller-provided rows. |
| search | GridSearchOptions | — | Controlled search toolbar: value, onChange, optional label, placeholder and disabled. The caller filters rows or fetches remote results; search is combined with sort and filter in the example. |
| columnMenus | boolean | true | Shared App-style header menus: sort, freeze/unfreeze, move and hide. Hiding requires columnSettings. Custom renderHeaderCell and the selection column are preserved. Uses the same controlled columnSettings state. |
| rowKeyGetter | (row: R) => Key | — | Stable row identity; required for selection. |
| sort | GridSortOptions | — | Built-in Sort menu. fields, value, onChange; optional disabled and maxSorts. Array order is sort priority. Controls header sorting unless native sort props are supplied. |
| filter | GridFilterOptions | — | Built-in Filter menu. fields, value, onChange; optional disabled, maxConditions, maxDepth, contextLabel. Maximum 3 levels including the root; maxDepth defaults to 2 nested levels and can only lower that limit. Valid edits apply immediately. Incomplete edits remain in the local draft; external value changes reset it. |
| sort.fields / filter.fields | readonly QueryField[] | Required when enabled | Caller-defined field IDs, types, operators, choice lookups, and custom value editors. |
| columnSettings | boolean \| GridColumnSettings | false | true creates internal column settings. Pass columns, value, onChange, optional onReset/disabled for controlled settings. Visibility, order, and freeze are applied by DataGrid. |
| toolbar | ReactNode | — | Additional caller-defined grid actions. |
| containerClassName / toolbarClassName | string | — | Tailwind classes for the outer container and toolbar. className targets the grid itself. |
| sortColumns / onSortColumnsChange | SortColumn[] / callback | Derived from sort | Native overrides; keep them consistent with sort when using both. |
| selectedRows / onSelectedRowsChange | ReadonlySet<Key> / callback | — | Native row selection. |
| onRowsChange / columns[].renderEditCell | callback / component | — | Both are needed for editable columns. |
| rowHeight / headerRowHeight / className / ref | Native react-data-grid props | Native defaults | Row and header heights default to 40px. Remaining props are forwarded to react-data-grid. ref refers to the grid, not the toolbar. |
```ts
type QueryField = {
id: string; label: string
type: 'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'select' | 'multiSelect' | 'relation'
path?: string[]; options?: Choice[]; sortable?: boolean
operators?: { id: string; label: string; input?: 'none' | 'single' | 'multiple' | 'range' | 'relative' }[]
renderValue?: (props: { condition: FilterCondition; onChange: (value: FilterValue) => void; disabled?: boolean }) => ReactNode
}
type RecordSort = { field: string; direction: 'asc' | 'desc' }
type FilterCondition = { id: string; field: string; operator: string; value?: FilterValue }
type RecordFilter = { id?: string; conjunction: 'and' | 'or'; conditions: (FilterCondition | (RecordFilter & { id: string }))[] }
type FilterValue = string | number | boolean | null | (string | number)[] | { direction: 'past' | 'next'; amount: number; unit: 'day' | 'week' | 'month' }
type GridSortOptions = { fields: readonly QueryField[]; value: RecordSort[]; onChange: (value: RecordSort[]) => void; disabled?: boolean; maxSorts?: number }
type GridFilterOptions = { fields: readonly QueryField[]; value: RecordFilter; onChange: (value: RecordFilter) => void; disabled?: boolean; maxConditions?: number; maxDepth?: number; contextLabel?: string }
type GridColumnState = { id: string; visible: boolean; frozen?: boolean }
type GridColumnSettings = { columns: readonly { id: string; label: string; required?: boolean; canFreeze?: boolean }[]; value: GridColumnState[]; onChange: (value: GridColumnState[]) => void; onReset?: () => void; disabled?: boolean }
```
Sort, Filter, and Columns are built-in DataGrid features, not separate public components. Sorting/filtering emit query state; the caller supplies the resulting rows for local or remote data. Do not sort individual loaded pages. Column settings apply locally. Record List exposes these options inside grid. Editable filtered collections must merge changed rows by stable ID into their source data.