QEditableList
A spreadsheet-style editable grid with typed columns and add/remove rows.
Updated
const [data, setData] = useState([
{ name: "Widget", qty: 3, price: 9.99 },
{ name: "Gadget", qty: 1, price: 19.99 },
]);
<QEditableList
columns={[
{ key: "name", header: "Name", type: "text", placeholder: "Item name" },
{ key: "qty", header: "Qty", type: "number", width: 90 },
{ key: "price", header: "Price", type: "currency", width: 120 },
]}
data={data}
onChange={setData}
createEmpty={() => ({ name: "", qty: 1, price: 0 })}
addLabel="Add item"
/>A spreadsheet-style editable grid: one row per record, one typed cell per column. Column types are text, number, currency, select, combobox, checkbox, date, monthday, and computed — the searchable combobox picker is just one of those types. Built for nested/repeating data (a parent form's list of sub-rows) with keyboard navigation (Enter/Tab/Arrows) and add/remove-row controls.
Installation
railbase ui add QEditableList
Note
railbase ui add also copies the button, checkbox, command, input, popover, select, tooltip components — they ship alongside this component automatically.
Usage
import {
QEditableList,
type QEditableColumn,
} from "@/lib/ui/QEditableList.ui";
type Line = { sku: string; qty: number; unit: string };
const columns: QEditableColumn<Line>[] = [
{ key: "sku", header: "SKU", type: "combobox", options: skuOptions },
{ key: "qty", header: "Qty", type: "number", min: 0 },
{ key: "unit", header: "Unit", type: "select", options: unitOptions },
];
<QEditableList
columns={columns}
data={rows}
onChange={setRows}
createEmpty={() => ({ sku: "", qty: 0, unit: "" })}
showAddButton
/>
The host owns the data row array and onChange; the component owns layout, per-cell inputs, and add/remove-row controls. createEmpty builds a blank row when one is added. Per-cell choices for select/combobox columns live in each column's options ({ value, label, group? }), not a top-level prop.