Toggle Sidebar B
AppearanceLight & dark mode D

Email Recipients Input

A growable list of email fields with add and remove, for the "who gets notified" half of a settings form. Binds to a plain string array, so the value goes straight into a JSON settings column with no reshaping.

Default

v-model binds an array of strings. Each entry is one row; the trash button splices it out.

Replay preview

Everyone here gets a copy of each new reservation.

Empty

An empty array renders the add button on its own. There is no zero-state row, so the list only takes vertical space once someone asks for it.

Replay preview

Custom labels

label, description and addLabel are the whole copy surface. Leave description off and the block tightens to the label alone.

Replay preview

Sent the embargoed release 24 hours before it goes public.

Validation

The rows are type="email" inputs and nothing more. Blank rows, duplicates and malformed addresses all survive until the form is submitted, so filter and validate on the way out rather than expecting the component to have done it.

js
// Before sending: drop blanks, trim, de-duplicate.
const recipients = [...new Set(emails.value.map((e) => e.trim()).filter(Boolean))];

API Reference

EmailRecipientsInput

PropTypeDefaultDescription
modelValuestring[][]The addresses. Supports v-model. Mutated in place: add pushes an empty string, remove splices by index.
labelstring""Heading above the list. Rendered in a Label, not tied to any one input.
descriptionstring""Muted helper line under the label. Omitted entirely when empty.
addLabelstring"Add Email"Text on the add button.
EventDescription
update:modelValueFires when a row is added or removed. Enables v-model.

Accessibility

Keyboard shortcuts and ARIA behavior.

Shortcut Description
TabMoves through each email field and its remove button in order.
EnterOn the add button, appends an empty row. Focus stays on the button.
  • Every remove button carries aria-label="Remove email". With several rows on screen a screen reader hears the same name repeatedly, so the row's own input is what distinguishes them.
  • The label is a heading for the group rather than a for/id pair, because the group has no single input to point at.