Installation
Nothing to add. This component ships as source in your download, so it is already in your project.
src/vui/record-form.tsx@viliha/vui-react/record-formThe exported names are at the top of that file. The import path is an alias the download's tsconfig.json points at src/vui/, so you can move that folder and change one line rather than every file that imports from it.
Usage
import { RecordDetailPanel, RecordForm, RecordFormPanel } from "@viliha/vui-react/record-form";Exports
Everything this family exports. They are read from the source, so this list is what the package actually ships.
| Prop | Type | Default |
|---|---|---|
| RecordDetailPanel | component | — |
| RecordForm | component | — |
| RecordFormPanel | component | — |
RecordDetailPanel props
| Prop | Type | Default | What it does |
|---|---|---|---|
| fields | RecordField<T>[] | — | |
| row | T | — | Initial values; the panel edits a local buffered copy until Save. |
| singular | string | — | |
| icon? | IconType | — | |
| getPrimary | (row: T) => { title: string; initials: string; subtitle?: string; } | — | |
| readOnly? | boolean | false | Read-only (View) vs editable (Edit / Add). |
| onEdit? | () => void | — | Switch a read-only panel into edit mode. |
| onSave | (row: T, then?: FormActionOutcome) => void | — | Commit the buffered draft to the table. `then` carries the acting button's `after`, so "Save & New" can hand the form a blank record. |
| onCancel | () => void | — | Discard the draft (and drop the row if it was never saved). |
| layout? | "panel" | "page" | "panel" | "panel" = slide-over (default); "page" = full-page form. |
| columns? | 1 | 2 | 1 | Full-page form column count. Default 1. |
| isNew? | boolean | false | New (unsaved) record — drives the "Create new …" breadcrumb. |
| title? | string | — | Plural collection title (e.g. "Organizations") — the clickable parent crumb. |
| onHome? | () => void | — | Navigate to Home from the breadcrumb. |
| formDescription? | string | — | Intro text for the documentation panel. |
| persistKey? | string | — | Persist the in-progress draft under this key (e.g. the route), so a half-filled form survives leaving and returning via the open-tabs strip. |
| formActions? | FormActionsConfig<T> | — | Footer buttons. An array replaces Cancel + Save (or Close + Edit in view mode); a function receives those defaults so you can add, reorder or swap one without restating the rest. |
| renderFooter? | (ctx: FormActionContext<T>) => React.ReactNode | — | Replace the whole footer. The array covers almost everything, so reach for this only when it genuinely can't express the layout you need. |
| formSlots? | FormSlot<T>[] | — | Your own content between the fields — a callout, a preview, a custom pair of controls. Each slot renders as a full-width row inside its section. |
| behaviour? | BehaviourConfig | — | Behaviour, already resolved by the table so a per-table prop reaches the form as well as the rows. |
| formRows? | FormRow[] | — | The form's rows: which sections sit side by side on each one. Up to three per row stay readable. |
| sectionColumns? | SectionColumns | — | |
| sections? | FormSection[] | — | Section metadata (order, description) when you aren't declaring `rows`. |
| crumbs? | Crumb[] | — | Page-form breadcrumb override (fully configurable). |
RecordForm props
It takes no props of its own. Everything you pass reaches the underlying Omit<DetailPanelProps<T>, "layout"> primitive, so every attribute it accepts works here unchanged and nothing is invented on top.
RecordFormPanel props
It takes no props of its own. Everything you pass reaches the underlying Omit<DetailPanelProps<T>, "layout"> primitive, so every attribute it accepts works here unchanged and nothing is invented on top.
Customize
Every value this component draws comes from the theme: the colours, the radius, the control height and the type scale. Change a token and this moves with everything else, which is the difference between theming the product and overriding a component. See Theming for the token contract, and Swapping defaults for replacing the markup itself.