Railbase
GPTClaude

QEditableList

A spreadsheet-style editable grid with typed columns and add/remove rows.

Updated

Editable rows
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.

Was this page helpful?Thanks for your feedback!