Components

DualList

A double list used to pick items from one list to another

Usage

Use MeDualList to let users pick items from an available column into a selected column (and back). Bind the selection with v-model, pass the full list of options, and use value-key plus value-label when items are objects so rows match and display correctly.

Loading preview...
<template>
  <div class="w-full">
    <MeDualList
      v-model="selected"
      value-label="label"
      value-key="id"
      :right-error="selected.length === 0 && 'Select at least one available value'"
      :left-error="selected.length === list.length && 'Let at least one available value unselected'"
      :list="list"
    />
  </div>
</template>

<script setup>
const selected = ref([])

const list = ref([
  { id: 1, label: 'Guilherme Santos Araujo Rocha' },
  { id: 2, label: 'Ian Santos Araujo Rocha' },
  { id: 3, label: 'Caio Santos Araujo Ferreira' },
  { id: 4, label: 'Maria Santos Costa Ferreira' },
  { id: 5, label: 'João Souza Costa Batista' },
  { id: 6, label: 'Ana Souza Costa Batista' },
  { id: 7, label: 'Pedro Souza Melo Paiva' },
  { id: 8, label: 'Carla Souza Melo Paiva' },
  { id: 9, label: 'Raul Silva Melo Garcia' },
  { id: 10, label: 'Vinicius Silva Brasil Garcia' },
  { id: 11, label: 'Bruna Silva Brasil Leite' },
  { id: 12, label: 'Matheus Silva Brasil Leite' }
])
</script>

Labels, descriptions, help, and empty text

Each column is a form field region. You can set titles (left-box-label, right-box-label), descriptions under the label (left-box-description, right-box-description), help text (left-box-help, right-box-help), and the message when a box has no rows (left-box-empty-text, right-box-empty-text).

Pick one or more items to move to the right.

Empty list illustration
No options left.
Use the + icon on a row or “Adicionar todas”.

These values will be submitted with the form.

Empty list illustration
Nothing selected yet.
Use − to remove a row or “Remover todas”.
<template>
  <div class="w-full">
    <MeDualList
      left-box-label="Available"
      right-box-label="Chosen"
      left-box-description="Pick one or more items to move to the right."
      right-box-description="These values will be submitted with the form."
      left-box-help="Use the + icon on a row or “Adicionar todas”."
      right-box-help="Use − to remove a row or “Remover todas”."
      left-box-empty-text="No options left."
      right-box-empty-text="Nothing selected yet."
    />
  </div>
</template>

Required and disabled

Set required to mark both list regions as required in the form UI. Set disabled to disable both columns and the Adicionar todas / Remover todas actions (individual row actions are disabled as well).

Empty list illustration
No options available
Empty list illustration
No options selected
Two
Three
One
<template>
  <div class="w-full flex flex-col gap-8">
    <MeDualList required />

    <MeDualList
      v-model="selectedDisabled"
      disabled
      :list="items"
    />
  </div>
</template>

<script setup>
const items = ref(['One', 'Two', 'Three'])

const selectedDisabled = ref([items.value[0]])
</script>

Draggable

When draggable is true, both the available (left) and selected (right) lists display a drag handle icon for each item. You can drag items from the available list to the selected list to include them, or from the selected list back to the available list to deselect them. Only the selected (right) list allows items to be reordered via drag-and-drop. When a search/filter is active in either list, you can still move items between lists, but reordering the selected items is disabled to prevent conflicts between filtering and sorting.

Fourth
Third
Second
First
Empty list illustration
No options selected
<template>
  <div class="w-full">
    <MeDualList
      draggable
      :list="['Fourth', 'Third', 'Second', 'First']"
    />
  </div>
</template>

Input, icons left and icons right

The input, icons-left, and icons-right slots allow you to add custom content to each item in the selected list. The input slot displays its content to the left of the icons and is always visible. The icons-left and icons-right slots can be used to add icons or action buttons.

Item B
Item A
<template>
  <div class="w-full">
    <MeDualList
      v-model="selected"
      :list="items"
      value-label="label"
      value-key="id"
    >
      <template #icons-left="{ item }">
        <MeTooltip
          text="This button is in the icons-left slot"
          arrrow
        >
          <UIcon name="ic:round-arrow-circle-left" />
        </MeTooltip>
      </template>

      <template #icons-right="{ item }">
        <MeTooltip
          text="This button is in the icons-right slot"
          arrrow
        >
          <UIcon name="ic:round-arrow-circle-right" />
        </MeTooltip>
      </template>

      <template #input="{ item }">
        <MeInput placeholder="input" />
      </template>
    </MeDualList>
  </div>
</template>

<script setup>
const items = ref([{ id: 1, label: 'Item A' }, { id: 2, label: 'Item B' }])

const selected = ref([items.value[0]])
</script>

API

Props

PropDefaultType
namestring
Name of the form field (left list box).
requiredfalseboolean
Marks the control as required on both list boxes.
disabledfalseboolean
Disables both list boxes and the add/remove-all actions.
draggablefalseboolean
When true, the right list shows a drag handle and selected items can be reordered (drag is disabled while the search field has text).
list[]T[]
Full set of options. Items already in modelValue appear only on the right.
modelValue[]T[]
Selected items. Use v-model to bind this prop.
valueKeystring | number | ((item: T) => string | number) | undefined
Resolves the stable id used to tell items apart (object path, key, or getter). If not provided, the exact value of the item will be used (recommended for primitive values). Required for object items so selection matches correctly.
valueLabelstring | number | ((item: T) => string | number) | undefined
Resolves the text shown for each row (object path, key, or getter). If omitted, the exact value of the item will be used—this works directly for primitive values.
leftErrorboolean | string
Error state or message for the left list box (FormField).
rightErrorboolean | string
Error state or message for the right list box (FormField).
errorPatternstring | RegExp
Pattern used to match and highlight the erroneous segment in the error message. Forwarded to FormField.
eagerValidationboolean
When true, validates as soon as the box fields mounts. Forwarded to Nuxt UI FormField.
validateOnInputDelaynumber
Delay in milliseconds before validating on input. Forwarded to FormField.
leftBoxLabel'Available'string
Label for the left box.
leftBoxDescriptionstring
Description shown under the left box label.
leftBoxEmptyText'No options available'string
Text when there are no items left to pick.
leftBoxHelpstring
Help text for the left list box.
rightBoxLabel'Selected'string
Label for the right box.
rightBoxDescriptionstring
Description shown under the right box label.
rightBoxEmptyText'No options selected'string
Text when nothing is selected.
rightBoxHelpstring
Help text for the right list box.

Emits

EventType
update:model-value[value: T[]]

Slots

SlotType
input{ item: T }
icons-left{ item: T }
icons-right{ item: T }