Data input

Repeater

Rows of fields that a reader adds and removes, within a minimum and a maximum, numbered in order for the form.

Class nameTypeDescription
repeaterplf:repeaterComponentHolds the rows, their template and the add button
repeater-listplf:repeater-listPartThe list of rows
repeater-rowplf:repeater-rowPartA row: its fields share the width, then its buttons

Default

Name a row’s fields with [] in the template, such as emails[] or links[][url]; the script numbers the rows in order.

Email addresses

Add up to 5 addresses where we can reach you.

Several fields

Write the template’s ids as for one field; each new row takes its own, and its labels follow.

Links

Limits

The remove buttons are disabled at the minimum and the add button at the maximum.

Allowed domains

At least one and up to three domains.

Reorder

With the Sortable extension, rows move by their handle and their names follow the new order.

Onboarding steps

Conditional field in a row

A condition in the template names its row’s field with [] too, and follows the row’s number.

Notification channels

Confirm removal

Your script cancels the removal, asks with PLF.Dialog.fire() and removes the row with instance.remove(row), whose reason is api.

Team members

JavaScript

The add and remove buttons need JavaScript, so author them hidden; without it the rows the page loaded still submit. The Full script (pelatform-ui.min.js) and the extension scripts after it start every component on page load, with no code of your own; with Core and single files, the last line starts them. For markup you add later, see Dynamic content.

<link rel="stylesheet" href="pelatform-ui.min.css">
<link rel="stylesheet" href="extensions/sortable.min.css">
<link rel="stylesheet" href="icons/icons.min.css">
<script src="pelatform-ui.min.js" defer></script>
<script src="extensions/sortable.min.js" defer></script>
<link rel="stylesheet" href="pelatform-ui.prefixed.min.css">
<link rel="stylesheet" href="extensions/sortable.prefixed.min.css">
<link rel="stylesheet" href="icons/icons.prefixed.min.css">
<script src="pelatform-ui.min.js" defer></script>
<script src="extensions/sortable.min.js" defer></script>
Attribute Purpose
data-plf-repeater The container: one <ol> or <ul> of <li> rows, one <template> holding one <li> row, and its add buttons. The template names its fields with [] after one base, such as links[][url]. After each addition, removal and move, the script numbers every row’s names in order (links[0][url]), and gives a new row’s ids their own values, which its for and aria-* references follow
data-plf-min, data-plf-max On the container: the fewest and the most rows, whole numbers; 0 and no limit by default. The remove buttons are disabled at the minimum and the add buttons at the maximum; the script adds no rows by itself
data-plf-repeater-add On a button outside the rows: adds a row from the template at the end and focuses its first field
data-plf-repeater-remove On a button in a row: removes the row and focuses the row now in its place, the one before it or an add button. The script describes it by its row’s first field, so a screen reader hears that field’s value after the button’s name. In a form, write type="button" on every add and remove button, the template’s included
data-plf-sortable On the <ol> or <ul>, with the Sortable extension: rows move by their handle once the list holds two; the script gives each row a data-plf-value it lacks
data-plf-show-if In a row, a condition that names its row’s field with [] in the template, such as links[][type]=custom
Method Behavior
PLF.Repeater.getOrCreateInstance(element) Returns the instance, creating it for valid markup
PLF.Repeater.getInstance(element) Returns the instance or null
instance.add() Adds a row at the end and returns it, without moving focus; null at the maximum or when canceled
instance.remove(row) Removes one of its rows; false at the minimum, for another element or when canceled
instance.getRows() Returns the rows, in order
instance.destroy() Removes the listeners and hides the buttons again; the rows and their values stay

With ESM, import Repeater from @pelatform/ui/components/repeater.

Events

Event When
plf:repeater:before-add Before a row is added; cancelable. Its row is not in the page yet
plf:repeater:add After the row is in the page, numbered, and its components have started
plf:repeater:before-remove Before a row is removed; cancelable, such as to ask for confirmation
plf:repeater:remove After the row has left the page and the others are numbered again

Each event’s detail:

Property Value
instance The Repeater instance
reason trigger, or api from a method
trigger The add or remove button, or null from a method
row The row added or removed
index The row’s zero-based position

Events bubble from the container. A form reset brings back the rows the page loaded, in their order and with their values, and sends no events.

Keyboard

Key Action
Tab, Shift+Tab Move through the rows’ fields and buttons, then the add button
Enter, Space On an add or remove button, adds or removes a row
Space, Enter, then the arrow keys On a sortable row’s handle, move the row, as in Sortable

React

Repeater from @pelatform/react renders the fieldset, its rows and the add button, and its function child renders each row’s content; it keeps each row’s React key, disables the buttons at min and max, and moves focus as the script does. As its child and createItem are functions, the component that renders it is a client component ('use client').

Prop Values Default
legend The legend (field-legend), which names the rows None
help Help text after the legend (field-help) None
items The rows’ items, which the application changes in onItemsChange Its own state
defaultItems The items it starts with when the application does not set items No rows
onItemsChange (items), called with the new items when a button adds or removes a row None
createItem (), which returns the item of a row the add button adds Required
min The fewest rows, at which the remove buttons are disabled 0
max The most rows, at which the add button is disabled No limit
addLabel The add button’s text Required
children (item, row), which renders a row’s content Required

The child’s row:

Property Value
index The row’s position from 0, which numbers its fields’ names, as emails[${index}]
fieldId The id for the row’s first field, on its control or its Field; it describes the remove button, so a screen reader hears that field’s value after the button’s name
removeProps The remove button’s props, spread on a Button or an InputGroupAction: type="button", aria-describedby, disabled at min and the click that removes the row

The other props are a fieldset’s, className and ref included. Without items, a form reset brings back the rows it started with.

CSS variables

Override on a root or on a single repeater.

Variable Default
--plf-repeater-gap --plf-space-4, 1rem (16px), between the rows, the list and the add button
--plf-repeater-field-width 12rem (192px), the narrowest a row’s field gets before the row wraps onto another line, so two fields stack on a phone

Built with Pelatform UIv0.1.0

Components

Getting started

Foundations

Components

Actions

Data display

Navigation

Feedback

Data input

Layout

Advanced

Integrations

Blocks

Application

Authentication

Icons