Repeatable Field Group React component
A set of fields people can repeat: add a row, remove one, drag rows into order. Rows grow in and slide out, focus lands in the new row, Enter in the last row adds another, and min / max limits keep the list in bounds.
About the Repeatable Field Group component
Repeatable Field Group is a form section where people add, edit, remove and reorder rows of the same fields, like a list of teammates to invite with an email and a role each. New rows slide in, removed rows slide out to the side, and rows can be dragged into a new order by their handle while the others make room.
fields describes the columns: each has a key, a label, a type (text, email, number, url or select), an optional placeholder, options for selects, a starting value for new rows and a grow factor for its width. The rows come out of onValueChange as plain objects keyed by field, such as { email, role }. min and max limit the number of rows, and a counter shows how many are used. label, description and addLabel set the texts, and reorderable={false} hides the drag handles.
When to use it
Use Repeatable Field Group when people enter a list of similar things of unknown length: invites, links, phone numbers, line items, key / value pairs, custom fields.
For a list of existing items to sort, use Sortable List. For picking from known options, use Multi Select or Checkbox Group.
Installation
Add the Repeatable Field Group component to your project with the shadcn CLI. It lands in components/repeatable-field-group.tsx as plain React + Tailwind CSS source you own and can edit.
npx shadcn@latest add @reactframe/repeatable-field-groupOr copy the source by hand and install its dependencies:
npm install motion clsx tailwind-mergeProps
<RepeatableFieldGroup /> accepts 12 props, all optional.
| Prop | Type | Default |
|---|---|---|
| fields | RepeatableField[] | DEFAULT_FIELDS |
| value | Record<string, string>[] | — |
| defaultValue | Record<string, string>[] | DEFAULT_ROWS |
| onValueChange | (rows: RepeatableRow[]) => void | — |
| min Rows can't be removed below this. | number | 1 |
| max The add button disables at this many rows. | number | 6 |
| label | string | "Invite teammates" |
| description | string | "They'll get an email with a link to join." |
| addLabel | string | "Add another" |
| reorderable Show drag handles to reorder rows. | boolean | true |
| theme | "dark" | "light" | "dark" |
| className | string | — |
- fieldsRepeatableField[]Default: DEFAULT_FIELDS
- valueRecord<string, string>[]
- defaultValueRecord<string, string>[]Default: DEFAULT_ROWS
- onValueChange(rows: RepeatableRow[]) => void
- min
Rows can't be removed below this.
numberDefault: 1 - max
The add button disables at this many rows.
numberDefault: 6 - labelstringDefault: "Invite teammates"
- descriptionstringDefault: "They'll get an email with a link to join."
- addLabelstringDefault: "Add another"
- reorderable
Show drag handles to reorder rows.
booleanDefault: true - theme"dark" | "light"Default: "dark"
- classNamestring
npm dependencies
Installed for you by the shadcn CLI.
Repeatable Field Group FAQ
- How does reordering work?
- Each row has a handle; drag it up or down and the other rows make room. Set reorderable={false} to hide the handles.
- Can I limit the number of rows?
- Yes. min stops removal below that count and max disables the add button; the counter shows how many are left.
- Is it keyboard friendly?
- New rows get focus in their first field, Enter in the last row adds another, and removing a row moves focus to the one that took its place.
- What shape is the value?
- An array of rows, each a plain object with one string per field key, for example [{ email: "maya@northwind.co", role: "admin" }]. Numbers are kept as strings, as the inputs give them, so convert them when you save.