Overview
The nuxtUIRepeater component is a special input component that allows you to create dynamic form sections where users can add, remove, clone, and reorder items. Perfect for managing lists like contacts, addresses, skills, or any repeatable data. Supports both button-based reordering and intuitive drag-and-drop functionality.
It is also imported and registered globally, so you can use it anywhere in your Nuxt app without additional imports.
Basic Usage
<template>
<FormKit type="form" @submit="handleSubmit">
<FormKit
type="nuxtUIRepeater"
name="contacts"
label="Contacts"
:new-item="{ name: '', email: '' }"
>
<FormKit
type="nuxtUIInput"
name="name"
label="Name"
validation="required"
/>
<FormKit
type="nuxtUIInput"
name="email"
input-type="email"
label="Email"
validation="required|email"
/>
</FormKit>
</FormKit>
</template>
<script setup lang="ts">
const handleSubmit = (data: any) => {
console.log('Contacts:', data.contacts)
}
</script>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Schema-Based Repeater
Use repeaters in schema definitions:
const schema = [
{
$formkit: 'nuxtUIRepeater',
name: 'experiences',
label: 'Work Experience',
newItem: {
company: '',
position: '',
years: 0
},
children: [
{
$formkit: 'nuxtUIInput',
name: 'company',
label: 'Company',
validation: 'required'
},
{
$formkit: 'nuxtUIInput',
name: 'position',
label: 'Position',
validation: 'required'
},
{
$formkit: 'nuxtUIInputNumber',
name: 'years',
label: 'Years',
min: 0
}
]
}
]2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Props
newItem
Default object for new items. Required.
<FormKit
type="nuxtUIRepeater"
:new-item="{ name: '', email: '', phone: '' }"
/>2
3
4
Button Configuration
Control which buttons are displayed:
<FormKit
type="nuxtUIRepeater"
name="items"
:hide-button-group="false"
:hide-move-buttons="false"
:display-clone-button="true"
:display-add-button="true"
:display-delete-button="true"
/>2
3
4
5
6
7
8
9
Min/Max Items Constraints
Control the minimum and maximum number of items allowed:
<FormKit
type="nuxtUIRepeater"
name="contacts"
:new-item="{ name: '', phone: '' }"
:min-items="1"
:max-items="5"
>
<!-- form fields -->
</FormKit>2
3
4
5
6
7
8
9
Props:
- minItems - Minimum number of items required (default: 0). When reached, the delete button is automatically disabled.
- maxItems - Maximum number of items allowed (default: unlimited). When reached, add/insert/clone buttons are automatically disabled.
Insert Button
Customize the "Add Item" button:
<FormKit
type="nuxtUIRepeater"
name="skills"
insert-button-label="Add Skill"
insert-button-size="lg"
insert-button-class="mb-4"
:always-display-insert-button="true"
/>2
3
4
5
6
7
8
Button Styling
<FormKit
type="nuxtUIRepeater"
name="items"
button-size="sm"
button-group-class="flex gap-2"
button-group-item-class="flex-shrink-0"
/>2
3
4
5
6
7
List Styling
<FormKit
type="nuxtUIRepeater"
name="items"
list-class="space-y-4"
list-item-class="p-4 border rounded-lg"
/>2
3
4
5
6
Drag and Drop Reordering
Enable drag-and-drop reordering with a drag handle:
<FormKit
type="nuxtUIRepeater"
name="tasks"
:new-item="{ title: '', priority: 'medium' }"
:display-drag-handle="true"
drag-handle-class="cursor-grab active:cursor-grabbing"
drag-handle-icon-class="i-lucide-grip-vertical"
>
<!-- form fields -->
</FormKit>2
3
4
5
6
7
8
9
10
Props:
- displayDragHandle - Enable drag-and-drop reordering (default: false)
- dragHandleClass - CSS class for the drag handle container (default: 'formkit-repeater-drag-handle')
- dragHandleIconClass - Icon class for the drag handle (default: 'i-lucide-grip-vertical')
When drag-and-drop is enabled:
- Items can be reordered by dragging the handle icon
- A visual indicator shows the drop target during dragging
- Move up/down buttons can be hidden with
:hide-move-buttons="true"if only drag-and-drop is desired
Auto-Animate
Repeaters automatically use @formkit/auto-animate for smooth animations when items are added, removed, or reordered.
Configure Animation
In your formkit.config.ts:
import { createAutoAnimatePlugin } from '@formkit/addons'
export default {
plugins: [
createAutoAnimatePlugin(
{
/* optional AutoAnimate config */
// default:
duration: 250,
easing: 'ease-in-out',
},
{
/* optional animation targets object */
// default:
global: ['outer', 'inner'],
form: ['form'],
// for nuxtUIRepeater:
nuxtUIRepeater: ['input'],
},
),
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Examples
Contact List
<FormKit
type="nuxtUIRepeater"
name="contacts"
label="Emergency Contacts"
:new-item="{ name: '', phone: '', relationship: '' }"
insert-button-label="Add Contact"
>
<FormKit
type="nuxtUIInput"
name="name"
label="Name"
validation="required"
/>
<FormKit
type="nuxtUIInput"
name="phone"
input-type="tel"
label="Phone"
validation="required"
/>
<FormKit
type="nuxtUISelect"
name="relationship"
label="Relationship"
:options="['Family', 'Friend', 'Colleague', 'Other']"
/>
</FormKit>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Product Variants
<FormKit
type="nuxtUIRepeater"
name="variants"
label="Product Variants"
:new-item="{ size: '', color: '', price: 0, stock: 0 }"
list-item-class="grid grid-cols-4 gap-4"
>
<FormKit
type="nuxtUISelect"
name="size"
label="Size"
:options="['XS', 'S', 'M', 'L', 'XL']"
/>
<FormKit
type="nuxtUIColorPicker"
name="color"
label="Color"
/>
<FormKit
type="nuxtUIInputNumber"
name="price"
label="Price"
:min="0"
:step="0.01"
/>
<FormKit
type="nuxtUIInputNumber"
name="stock"
label="Stock"
:min="0"
/>
</FormKit>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Skills with Tags
<FormKit
type="nuxtUIRepeater"
name="skillCategories"
label="Skill Categories"
:new-item="{ category: '', skills: [] }"
>
<FormKit
type="nuxtUIInput"
name="category"
label="Category"
validation="required"
/>
<FormKit
type="nuxtUIInputTags"
name="skills"
label="Skills"
placeholder="Add skills..."
/>
</FormKit>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Drag-and-Drop Task List
<FormKit
type="nuxtUIRepeater"
name="tasks"
label="Task List"
:new-item="{ title: '', priority: 'medium', status: 'todo' }"
:display-drag-handle="true"
:hide-move-buttons="true"
list-item-class="flex items-center gap-4 p-4 border rounded-lg hover:bg-gray-50"
>
<FormKit
type="nuxtUIInput"
name="title"
label="Task"
validation="required"
/>
<FormKit
type="nuxtUISelect"
name="priority"
label="Priority"
:options="['low', 'medium', 'high']"
/>
<FormKit
type="nuxtUISelect"
name="status"
label="Status"
:options="['todo', 'in-progress', 'done']"
/>
</FormKit>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
This example enables drag-and-drop reordering and hides the traditional up/down buttons, providing a modern UX for task management.
Team Members with Constraints
<FormKit
type="nuxtUIRepeater"
name="teamMembers"
label="Team Members"
:new-item="{ name: '', role: '', email: '' }"
:min-items="2"
:max-items="10"
insert-button-label="Add Team Member"
>
<FormKit
type="nuxtUIInput"
name="name"
label="Name"
validation="required"
/>
<FormKit
type="nuxtUISelect"
name="role"
label="Role"
:options="['Developer', 'Designer', 'Manager', 'QA']"
validation="required"
/>
<FormKit
type="nuxtUIInput"
name="email"
input-type="email"
label="Email"
validation="required|email"
/>
</FormKit>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
This example requires at least 2 team members and allows a maximum of 10. The delete button will be disabled when only 2 items remain, and add/clone buttons will be disabled when 10 items are reached.
Features
- Add Items - Insert new items at the beginning or after specific items
- Remove Items - Delete items with confirmation
- Clone Items - Duplicate existing items
- Reorder - Move items up and down with buttons
- Drag and Drop - Intuitive drag-and-drop reordering with visual feedback
- Min/Max Constraints - Limit the minimum and maximum number of items
- Smooth Animations - Automatic animations for all operations
- Custom Styling - Full control over button and list appearance
- Validation - Built-in validation for repeated fields
Best Practices
- Always provide a
newItemprop with all required fields - Use validation on repeated fields for data integrity
- Use
min-itemsto enforce minimum requirements (e.g., at least one contact) - Use
max-itemsto prevent excessive data entry and improve UX - Consider UX - buttons are automatically disabled when constraints are reached
- Use drag-and-drop for better UX when managing sortable lists
- Hide move buttons (
:hide-move-buttons="true") when using drag-and-drop only - Use
list-item-classfor consistent spacing and layout - Provide clear labels for add/remove buttons