KQ-1669 · ATTENDEE/ROWS
Attendee Rows
A registration form whose guests are rows you can add, remove and move. Add guest unfolds a new row downward out of the button — its slot opens on springs.glide while the row swings down from -72° about its top edge — and removing folds it back up on the exit ease behind an undo chip whose hairline timer drains over five seconds. A row dragged by its grip lifts and follows the pointer 1:1 while the others glide out of its way, then settles into its slot on springs.snap with the release velocity; Alt+Arrow from anywhere in the row (or plain arrows on the grip) moves it with every row travelling on glide, and focus stays where it was.
Open day registration
Fernworks · Sat 14 Nov · Glass studio and print room
3 guests · 3 of 6 seats
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/attendee-rows
Props
- rows / defaultRows
- AttendeeRow[]
- default — / defaultAttendeeRows
- The guests in order, each { id, values }, controlled or initial. Removed rows waiting on Undo are not in it.
- onRowsChange
- (rows) => void
- default —
- Fires from every add, remove, undo, move and edit with the guests in order.
- fields
- AttendeeField[]
- default defaultAttendeeFields
- The columns: { key, label, kind: "text" | "email" | "select", options?, required?, placeholder?, autoComplete?, width?, span? }.
- seats
- number
- default 6
- Seats available; at the limit Add guest is aria-disabled and says why.
- onAdd
- (row, index) => void
- default —
- A guest was added.
- onRemove
- (row, index) => void
- default —
- A guest was removed; Undo is still offered.
- onRestore
- (row, index) => void
- default —
- Undo brought a removed guest back at its old place.
- onReorder
- (rows, from, to) => void
- default —
- A drag, Alt+Arrow or grip arrow moved a guest.
- onSubmit
- (rows) => void | Promise<void>
- default —
- Register with every row valid. A promise shows progress on the button; a rejection keeps every row and offers Try again.
- rowStyle
- "lines" | "cards" | "striped"
- default "lines"
- Rows set apart by hairlines like a table, as raised cards, or by alternating washes.
- density
- "compact" | "cozy" | "roomy"
- default "cozy"
- Field height (32, 36, 40px) and row padding.
- accent
- string
- default "var(--accent-bright)"
- Badges, seat pips, the lifted row's edge, the add button's plus and the submit fill, any CSS colour.
- undoMs
- number
- default 5000
- How long a removed row waits behind its undo chip; held while the chip is hovered or keyboard-focused.
- title
- string
- default "Open day registration"
- The form's heading and accessible name.
- event
- string
- default "Fernworks · Sat 14 Nov · Glass studio and print room"
- The event line under the heading.
- submitLabel
- string
- default "Register"
- The submit verb; the guest count follows it ("Register 3 guests").
- height
- number
- default 520
- Panel height in px; the rows scroll inside it.
- status
- "ready" | "loading"
- default "ready"
- Loading draws placeholder rows.
- disabled
- boolean
- default false
- Nothing can be edited, moved or sent.
- className
- string
- default —
- Classes for the outer container.
| Prop | Type | Default | Description |
|---|---|---|---|
| rows / defaultRows | AttendeeRow[] | — / defaultAttendeeRows | The guests in order, each { id, values }, controlled or initial. Removed rows waiting on Undo are not in it. |
| onRowsChange | (rows) => void | — | Fires from every add, remove, undo, move and edit with the guests in order. |
| fields | AttendeeField[] | defaultAttendeeFields | The columns: { key, label, kind: "text" | "email" | "select", options?, required?, placeholder?, autoComplete?, width?, span? }. |
| seats | number | 6 | Seats available; at the limit Add guest is aria-disabled and says why. |
| onAdd | (row, index) => void | — | A guest was added. |
| onRemove | (row, index) => void | — | A guest was removed; Undo is still offered. |
| onRestore | (row, index) => void | — | Undo brought a removed guest back at its old place. |
| onReorder | (rows, from, to) => void | — | A drag, Alt+Arrow or grip arrow moved a guest. |
| onSubmit | (rows) => void | Promise<void> | — | Register with every row valid. A promise shows progress on the button; a rejection keeps every row and offers Try again. |
| rowStyle | "lines" | "cards" | "striped" | "lines" | Rows set apart by hairlines like a table, as raised cards, or by alternating washes. |
| density | "compact" | "cozy" | "roomy" | "cozy" | Field height (32, 36, 40px) and row padding. |
| accent | string | "var(--accent-bright)" | Badges, seat pips, the lifted row's edge, the add button's plus and the submit fill, any CSS colour. |
| undoMs | number | 5000 | How long a removed row waits behind its undo chip; held while the chip is hovered or keyboard-focused. |
| title | string | "Open day registration" | The form's heading and accessible name. |
| event | string | "Fernworks · Sat 14 Nov · Glass studio and print room" | The event line under the heading. |
| submitLabel | string | "Register" | The submit verb; the guest count follows it ("Register 3 guests"). |
| height | number | 520 | Panel height in px; the rows scroll inside it. |
| status | "ready" | "loading" | "ready" | Loading draws placeholder rows. |
| disabled | boolean | false | Nothing can be edited, moved or sent. |
| className | string | — | Classes for the outer container. |