- Overview
- Anatomy
- Header
- Navigation
- Renderers
Data Cell
A lightweight editable cell for scalar document data: text, numbers, booleans, dates, times, and date-times.
Data Cell is the primitive for dense editable data surfaces. It renders the same compact cell shell for display and edit states, keeps editable cells display-only until interaction, and normalizes input behavior for common JSON scalar types.
"use client";
import * as React from "react";
import { ChevronDown } from "lucide-react";
import { Select as SelectPrimitive } from "radix-ui";
import {
DataCell,
type DataCellKind,
type DataCellValue,Installation
pnpm dlx shadcn@latest add @retab/data-cell
Usage
import { DataCell } from "@/components/ui/data-cell"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
<DataCell kind="number" value={-108.3} />
<DataCell
kind="number"
editable
value="-108.3"
onCommit={(value, meta) => {
// value is number | null for numeric cells
// meta.isValid distinguishes invalid input from an empty nullable value
}}
/>
<DataCell
kind="text"
editable
value="Committed"
draftValue={draft}
onDraftValueChange={setDraft}
onCommit={(value) => {
// value is string | null
}}
/>
const statusOptions = ["pending", "approved", "rejected"]
{isEditing ? (
<Select value={status} onValueChange={setStatus}>
<SelectTrigger className="h-8 min-h-8 w-full rounded-md border-transparent bg-transparent px-2 text-sm shadow-none">
<SelectValue placeholder="Select..." />
</SelectTrigger>
<SelectContent>
{statusOptions.map((option) => (
<SelectItem key={option} value={option}>
{option}
</SelectItem>
))}
</SelectContent>
</Select>
) : (
<DataCell kind="text" value={status} editable />
)}
API Reference
| Prop | Type | Default |
|---|---|---|
kind | DataCellKind | - |
value | DataCellValue | undefined |
mode | "display" | "edit" | "auto" | "auto" when editable, otherwise "display" |
editable | boolean | false |
disabled | boolean | false |
name | string | undefined |
placeholder | string | "—" |
dateTimeZone | "local" | "preserve" | "utc" | "local" |
formatValue | (value, meta) => React.ReactNode | undefined |
draftValue | string | undefined |
autoFocus | boolean | false |
onDraftValueChange | (value: string, meta: DataCellValueMeta) => void | undefined |
onCommit | (value, meta) => void typed by kind | undefined |
DataCell forwards standard data-*, ARIA, event, and style props to the
rendered cell. In auto mode, it renders the display cell first and only mounts
the edit control while hovered, focused, or explicitly activated. Number and
integer edit cells intentionally use native type="number" inputs and keep the
raw draft text separate from parsed commit metadata.
onCommit is discriminated by kind: number and integer cells commit
number | null, boolean cells commit boolean, and text/date/time/date-time
cells commit string | null.
DataCell only normalizes scalar input values. Schema policy belongs in the
adapter: nullable fields can turn empty null commits into stored null,
required numeric fields can ignore meta.isValid === false, and date-time
fields can opt into explicit timezone preservation with dateTimeZone. Enum
fields use the same scalar kind as their values, usually text, and keep option
validation or select controls in the schema adapter. Keep the enum adapter as a
display cell until hover, focus, or activation, then mount the real select.
Source
"use client";
import * as React from "react";
import { flushSync } from "react-dom";
import {
useDataCellActivationClickTail,
type DataCellActivationSource,
} from "@/registry/new-york-v4/ui/data-cell-activation";
import { DataCellControl } from "@/registry/new-york-v4/ui/data-cell-control";
import {
createDataCellControlState,