EditableTable
editable-tableEdits validated row and cell values directly within a data table.
Usage
Inline editing · Add and delete lines
Click the editable column to enter the editing state, editor customizes the cell editor (drop-down/number); addable + newRow adds rows, deletable deletes rows; onChange returns complete new data.
| Name | Role | Monthly salary | Actions |
|---|---|---|---|
| Zhang San | Administrator | ¥24,000 | |
| Li Si | Edit | ¥16,000 | |
| Wang Wu | Guest | ¥12,000 |
tsx
const [data, setData] = useState(rows);
const columns: EditableColumn<Row>[] = [
{ key: "name", title: "Name", editable: true, width: 160 },
{
key: "role", title: "Character", editable: true,
render: (v) => <Tag tone="brand">{ROLE_LABEL[v]}</Tag>,
editor: (value, onChange) => (
<select value={value} onChange={(e) => onChange(e.target.value)}>
{/* options… */}
</select>
),
},
{
key: "salary", title: "Monthly salary", editable: true, align: "right",
render: (v) => `¥${Number(v).toLocaleString()}`,
editor: (value, onChange) => (
<input type="number" value={value} onChange={(e) => onChange(Number(e.target.value))} />
),
},
];
<EditableTable
columns={columns}
data={data}
rowKey={(r) => String(r.id)}
onChange={setData}
deletable
addable
newRow={() => ({ id: nextId(), name: "", role: "viewer", salary: 0 })}
/>When to use
Use EditableTable for row-by-row entry inside quotations, invoice details, or staffing configuration. Use Table for read-only display, or ProTable for a full list page with search, toolbar, and pagination.
Import
ts
import { EditableTable } from "@hulianui/ui"Props
EditableTableProps<T>:
| Name | Type | Default | Description |
|---|---|---|---|
| columns* | EditableColumn<T>[] | — | Column definitions described below. |
| data* | T[] | — | Controlled data array. |
| rowKey* | (row: T) => string | — | Stable row key. |
| addable | boolean | false | Shows the add-row action; requires newRow. |
| newRow | () => T | — | Factory whose new row immediately enters edit mode. |
| deletable | boolean | false | Enables row deletion. |
| validateRow | (row: T) => boolean | — | Blocks save on a falsy result; the consumer renders errors. |
| className | string | — | Root class name. |
Events
| Event | Type | Description |
|---|---|---|
| onChange | (next: T[]) => void | Returns the complete next array after save, delete, or add. |
Slots
| Slot | Type | Description |
|---|---|---|
| summary | (data: T[]) => ReactNode | Renders raw tfoot content; the consumer controls <tr> and colSpan. |
EditableColumn<T>:
| Name | Type | Default | Description |
|---|---|---|---|
| key* | keyof T & string | — | Data key. |
| title* | ReactNode | — | Column title. |
| editable | boolean | false | Makes the cell editable; false stays read-only during editing. |
| render | (value, row) => ReactNode | — | Display renderer; defaults to the raw value. |
| editor | (value, onChange, row) => ReactNode | — | Edit renderer; defaults to a text input writing into the draft. |
| width | number | — | Width in pixels. |
| align | "left" | "center" | "right" | "left" | Cell alignment. |
Example
tsx
const [data, setData] = useState(rows);
const columns: EditableColumn<Row>[] = [
{ key: "name", title: "Name", editable: true, width: 160 },
{ key: "salary", title: "Monthly salary", editable: true, align: "right",
render: (v) => `$${Number(v).toLocaleString()}`,
editor: (v, onChange) => (
<input type="number" value={v as number}
onChange={(e) => onChange(Number(e.target.value))} />
) },
];
<EditableTable<Row>
columns={columns}
data={data}
rowKey={(r) => String(r.id)}
onChange={setData}
addable
deletable
newRow={() => ({ id: Date.now(), name: "", salary: 0 })}
/>Usage notes
- Data is controlled. Write
nextfromonChangeback to state or saves and row changes will not appear. validateRowonly blocks saving; render any validation message inside a customeditor.summaryis raw table-footer content, so the consumer owns column spans and alignment.
Related
Table · Book3D · ProTable · PricingTable · JsonViewer · List