DualList
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.
<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.
These values will be submitted with the form.
<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).
<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.
<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.
<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
| Prop | Default | Type |
|---|---|---|
name | string Name of the form field (left list box). | |
required | false | boolean Marks the control as required on both list boxes. |
disabled | false | boolean Disables both list boxes and the add/remove-all actions. |
draggable | false | boolean 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. |
valueKey | string | 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. | |
valueLabel | string | 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. | |
leftError | boolean | string Error state or message for the left list box (FormField). | |
rightError | boolean | string Error state or message for the right list box (FormField). | |
errorPattern | string | RegExp Pattern used to match and highlight the erroneous segment in the error message. Forwarded to FormField. | |
eagerValidation | boolean When true, validates as soon as the box fields mounts. Forwarded to Nuxt UI FormField. | |
validateOnInputDelay | number Delay in milliseconds before validating on input. Forwarded to FormField. | |
leftBoxLabel | 'Available' | string Label for the left box. |
leftBoxDescription | string Description shown under the left box label. | |
leftBoxEmptyText | 'No options available' | string Text when there are no items left to pick. |
leftBoxHelp | string Help text for the left list box. | |
rightBoxLabel | 'Selected' | string Label for the right box. |
rightBoxDescription | string Description shown under the right box label. | |
rightBoxEmptyText | 'No options selected' | string Text when nothing is selected. |
rightBoxHelp | string Help text for the right list box. |
Emits
| Event | Type |
|---|---|
update:model-value | [value: T[]] |
Slots
| Slot | Type |
|---|---|
input | { item: T } |
icons-left | { item: T } |
icons-right | { item: T } |