Skip to content

Conversation

@salehattari
Copy link

πŸ”— Linked issue

Resolves #5308

❓ Type of change

  • πŸ“– Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • πŸ‘Œ Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

πŸ“š Description

This PR introduces a new Repeater component.
It allows users to create dynamic, sortable lists of forms or items. It is designed to handle complex objects, supports custom templates, and is fully integrated with the Nuxt UI theme system.

  • Dependencies: This component utilizes @vueuse/integrations/useSortable (wrapping sortablejs).

Features

  • πŸ”„ Drag & Drop: Fully sortable items powered by useSortable (with touch support).
  • πŸŽ› Manual Sorting: Optional Up/Down buttons for better accessibility.
  • 🎨 Themeable: Built with tv (Tailwind Variants) supporting outline, soft, etc.
  • πŸ›‘ Limits: Built-in support for maxItems and minItems.
  • 🧩 Extensible Slots: Full control via slots.
  • ⌨️ Typed: Generic type support for complex models (T extends Record<string, any>).

Checklist

  • Component logic (src/runtime/components/Repeater.vue)
  • Theme configuration (src/theme/repeater.ts)
  • Playground example (playgrounds/nuxt/app/pages/components/repeater.vue)
  • Tests (test/components/Repeater.spec.ts)
  • Documentation (docs/content/docs/components/repeater.md)

Preview

URepeater.-.salehattari.mp4

Unifies emit overloads per @typescript-eslint/unified-signatures.
Removes unused toRef and stop; useSortable cleanup is already handled by vueuse via scope disposal.
@ta-inventions
Copy link

Hey man,
CI was failing due to unified-signatures lint rules and unused vars.
I pushed a fix PR against your branch that resolves this:
salehattari#1
Thx for this great work btw!

fix(ui): unify Repeater emits signatures and clean up unused vars - also fixed other CI errors
Fixes accessibility violations ("button-name") by adding aria-labels
to icon-only buttons. Labels are localized using Nuxt UI locale
infrastructure.
This resolves failing a11y snapshot tests in both nuxt and vue projects.
No visual changes.
@ta-inventions
Copy link

Hey @salehattari,
I pushed another PR against your branch that resolves the new CI failed test:
salehattari#2

fix(ui): add accessible labels to Repeater action buttons
@ta-inventions
Copy link

Hey @salehattari,
I pushed another PR against your branch that resolves the new CI failed typecheck:
salehattari#3

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 5, 2026

npm i https://pkg.pr.new/@nuxt/ui@5797

commit: a2bfc0a

@ta-inventions
Copy link

Hey, @atinux @TheAlexLichter - I'm not sure if I'm tagging the right people to address it but -
it seens that tiptap/core published a new version (3.15) like 2 hours ago:
{C5CFB12D-270F-47DE-9D6B-7A56A9EA27F2}
https://www.npmjs.com/package/@tiptap/core?activeTab=readme
And since the pnpm-lock.yaml on the root of the project is fixed to:
'@tiptap/core': specifier: ^3.14.0 version: 3.14.0(@tiptap/[email protected])
but the Install dependencies for the playground CI runs:
Run pnpm install --ignore-workspace
image
it ignores the root lock file and install the latest version of tiptap/core(3.15) which later on causes an error on the
Typecheck step of the playground because there is a mismatch between the 2 tiptap/core versions:
Types of property 'addNodeView' are incompatible. Type '((this: { name: string; options: any; storage: any; editor: import("/home/runner/work/ui/ui/node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@tiptap/core/dist/index").Editor; type: import("/home/runner/work/ui/ui/playgrounds/nuxt/node_modules/.pnpm/[email protected]/node_modules/prosemirr...' is not assignable to type '((this: { name: string; options: any; storage: any; editor: import("/home/runner/work/ui/ui/playgrounds/nuxt/node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@tiptap/core/dist/index").Editor; type: import("/home/runner/work/ui/ui/playgrounds/nuxt/node_modules/.pnpm/[email protected]/node_...'.

{2D3D0ED9-719C-4810-9CA4-37A0E086615A}

Any guidance? πŸ™

@caiotarifa
Copy link

Thanks @salehattari for your work on this PR! A Repeater is really needed, especially for forms.

Small naming thought: if the main goal is form usage (state + validation), maybe a name like FormRepeater (or UFormRepeater) could make that intent clearer.

A few points to consider:

  1. The UI of each item/card feels a bit β€œbig”. Maybe the title and the actions could stay on the same line, with a more compact spacing.
  2. It would be great to have a β€œsingle line” / β€œcompact” option for simple cases (like repeating only one field), without the full card structure.
  3. Accessibility is very important here: keyboard support, focus order, clear labels for icon-only buttons, and a good experience for screen readers.
  4. Form integration: it should work well with UForm state and Standard Schema validation (errors per item / per field, and predictable paths/keys).

For UI reference, I really like Filament’s Repeater: https://filamentphp.com/docs/3.x/forms/fields/repeater

It keeps the header/actions compact and works great in real forms.

With Buttons

With Collapsing

With 'One Line' Mode

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v4 #4488

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a Repeater Component for Nuxt UI Forms

3 participants