Listbox is used to select one or more values from a list of items.
npx volt-vue add Listbox
import Listbox from '@/volt/Listbox.vue';
Listbox is used with the v-model property for two-way value binding along with the options collection. Label and value of an option are defined with the optionLabel and optionValue properties respectively. Note that, when options are simple primitive values such as a string array, no optionLabel and optionValue would be necessary.
<template>
<div class="card flex justify-center">
<Listbox v-model="selectedCity" :options="cities" optionLabel="name" class="w-full md:w-56" />
</div>
</template>
<script setup lang="ts">
import Listbox from '@/volt/Listbox.vue';
import { ref } from 'vue';
const selectedCity = ref(null);
const cities = ref([
{ name: 'New York', code: 'NY' },
{ name: 'Rome', code: 'RM' },
{ name: 'London', code: 'LDN' },
{ name: 'Istanbul', code: 'IST' },
{ name: 'Paris', code: 'PRS' }
]);
</script>
An alternative way to highlight the selected option is displaying a checkmark instead.
<template>
<div class="card flex justify-center">
<Listbox v-model="selectedCity" :options="cities" optionLabel="name" checkmark :highlightOnSelect="false" class="w-full md:w-56" />
</div>
</template>
<script setup lang="ts">
import Listbox from '@/volt/Listbox.vue';
import { ref } from 'vue';
const selectedCity = ref(null);
const cities = ref([
{ name: 'New York', code: 'NY' },
{ name: 'Rome', code: 'RM' },
{ name: 'London', code: 'LDN' },
{ name: 'Istanbul', code: 'IST' },
{ name: 'Paris', code: 'PRS' }
]);
</script>
Listbox allows choosing a single item by default, enable multiple property to choose more than one. When the optional metaKeySelection is present, behavior is changed in a way that selecting a new item requires meta key to be present.
<template>
<div class="card flex justify-center">
<Listbox v-model="selectedCity" :options="cities" multiple optionLabel="name" class="w-full md:w-56" />
</div>
</template>
<script setup lang="ts">
import Listbox from '@/volt/Listbox.vue';
import { ref } from 'vue';
const selectedCity = ref(null);
const cities = ref([
{ name: 'New York', code: 'NY' },
{ name: 'Rome', code: 'RM' },
{ name: 'London', code: 'LDN' },
{ name: 'Istanbul', code: 'IST' },
{ name: 'Paris', code: 'PRS' }
]);
</script>
Options can be grouped when a nested data structures is provided. To define the label of a group optionGroupLabel property is needed and also optionGroupChildren is required to define the property that refers to the children of a group.
<template>
<Listbox v-model="selectedCity" :options="cities" optionLabel="label" optionGroupLabel="label" optionGroupChildren="items" class="w-full md:w-56" listStyle="max-height:250px">
<template #optiongroup="slotProps">
<div class="flex items-center">
<img :alt="slotProps.option.name" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.option.code.toLowerCase()} mr-2`" style="width: 18px" />
<span>{{ slotProps.option.label }}</span>
</div>
</template>
</Listbox>
</template>
<script setup lang="ts">
import Listbox from '@/volt/Listbox.vue';
import { ref } from 'vue';
const selectedCity = ref(null);
const cities = ref([
{
label: 'Germany',
code: 'DE',
items: [
{ label: 'Berlin', value: 'Berlin' },
{ label: 'Frankfurt', value: 'Frankfurt' },
{ label: 'Hamburg', value: 'Hamburg' },
{ label: 'Munich', value: 'Munich' }
]
},
{
label: 'USA',
code: 'US',
items: [
{ label: 'Chicago', value: 'Chicago' },
{ label: 'Los Angeles', value: 'Los Angeles' },
{ label: 'New York', value: 'New York' },
{ label: 'San Francisco', value: 'San Francisco' }
]
},
{
label: 'Japan',
code: 'JP',
items: [
{ label: 'Kyoto', value: 'Kyoto' },
{ label: 'Osaka', value: 'Osaka' },
{ label: 'Tokyo', value: 'Tokyo' },
{ label: 'Yokohama', value: 'Yokohama' }
]
}
]);
</script>
Listbox provides built-in filtering that is enabled by adding the filter property.
<template>
<div class="card flex justify-center">
<Listbox v-model="selectedCity" :options="cities" filter optionLabel="name" class="w-full md:w-56" />
</div>
</template>
<script setup lang="ts">
import Listbox from '@/volt/Listbox.vue';
import { ref } from 'vue';
const selectedCity = ref(null);
const cities = ref([
{ name: 'New York', code: 'NY' },
{ name: 'Rome', code: 'RM' },
{ name: 'London', code: 'LDN' },
{ name: 'Istanbul', code: 'IST' },
{ name: 'Paris', code: 'PRS' }
]);
</script>
Custom content for an option is displayed with the option slot that takes an option as a parameter. Additional available templating sections are filter and optionGroup.
<template>
<div class="card flex justify-center">
<Listbox v-model="selectedCountry" :options="countries" optionLabel="name" class="w-full md:w-56" listStyle="max-height:250px">
<template #option="slotProps">
<div class="flex items-center">
<img :alt="slotProps.option.name" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.option.code.toLowerCase()} mr-2`" style="width: 18px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</Listbox>
</div>
</template>
<script setup lang="ts">
import Listbox from '@/volt/Listbox.vue';
import { ref } from 'vue';
const selectedCountry = ref(null);
const countries = ref([
{ name: 'Australia', code: 'AU' },
{ name: 'Brazil', code: 'BR' },
{ name: 'China', code: 'CN' },
{ name: 'Egypt', code: 'EG' },
{ name: 'France', code: 'FR' },
{ name: 'Germany', code: 'DE' },
{ name: 'India', code: 'IN' },
{ name: 'Japan', code: 'JP' },
{ name: 'Spain', code: 'ES' },
{ name: 'United States', code: 'US' }
]);
</script>
VirtualScroller is used to render a long list of options efficiently like 100K records in this demo. The configuration is done with virtualScrollerOptions property, refer to the VirtualScroller for more information about the available options as it is used internally by Listbox.
<template>
<div class="card flex justify-center">
<Listbox v-model="selectedItem" :options="items" optionLabel="label" optionValue="value" :virtualScrollerOptions="{ itemSize: 38 }" class="w-full md:w-56" listStyle="height:250px" striped />
</div>
</template>
<script setup lang="ts">
import Listbox from '@/volt/Listbox.vue';
import { ref } from 'vue';
const selectedItem = ref();
const items = ref(Array.from({ length: 100000 }, (_, i) => ({ label: `Item #${i}`, value: i })));
</script>
Invalid state is displayed using the invalid prop to indicate a failed validation. You can use this style when integrating with form validation libraries.
<template>
<div class="card flex justify-center">
<Listbox v-model="selectedCity" :options="cities" optionLabel="name" :invalid="selectedCity === null" class="w-full md:w-56" />
</div>
</template>
<script setup lang="ts">
import Listbox from '@/volt/Listbox.vue';
import { ref } from 'vue';
const selectedCity = ref(null);
const cities = ref([
{ name: 'New York', code: 'NY' },
{ name: 'Rome', code: 'RM' },
{ name: 'London', code: 'LDN' },
{ name: 'Istanbul', code: 'IST' },
{ name: 'Paris', code: 'PRS' }
]);
</script>
When disabled is present, the element cannot be edited and focused.
<template>
<div class="card flex justify-center">
<Listbox v-model="selectedCity" disabled :options="cities" optionLabel="name" class="w-full md:w-56" />
</div>
</template>
<script setup lang="ts">
import Listbox from '@/volt/Listbox.vue';
import { ref } from 'vue';
const selectedCity = ref(null);
const cities = ref([
{ name: 'New York', code: 'NY' },
{ name: 'Rome', code: 'RM' },
{ name: 'London', code: 'LDN' },
{ name: 'Istanbul', code: 'IST' },
{ name: 'Paris', code: 'PRS' }
]);
</script>
Key distinctions to notice between the Volt Listbox and the PrimeVue Listbox.