QuesoSelectMultiple
A multiple select dropdown component that supports multiple selections from a list of options, two-way data binding with v-model
, and provides a consistent interface for form inputs. All form field components share the same base structure for consistent styling and behavior across your application.
Basic Usage
vue
<template>
<queso-select-multiple
name="tags"
label="Tags"
:options="tagOptions"
placeholder="Select tags"
v-model="selectedTags"
/>
</template>
<script setup>
import { ref } from "vue";
import { QuesoSelectMultiple } from "@allomambo/queso";
const selectedTags = ref([]);
const tagOptions = [
{ label: "Vue.js", value: "vue" },
{ label: "React", value: "react" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
];
</script>
Props
name
- Type:
string
- Required:
true
- Description: The name attribute for the select field.
label
- Type:
string
- Required:
false
- Description: The label text displayed above the select field.
id
- Type:
string
- Required:
false
- Description: The ID attribute for the select field (defaults to
name
if not provided).
options
- Type:
QuesoSelectMultipleOptions
- Required:
true
- Description: Array of options for the select dropdown. Each option must have a
label
andvalue
.
placeholder
- Type:
string
- Required:
false
- Description: Placeholder text displayed when no options are selected.
isRequired
- Type:
boolean
- Default:
false
- Description: Whether the field is required.
isDisabled
- Type:
boolean
- Default:
false
- Description: Whether the field is disabled.
isReadOnly
- Type:
boolean
- Default:
false
- Description: Whether the field is read-only.
isError
- Type:
boolean
- Default:
false
- Description: Whether the field has an error state.
extraAttributes
- Type:
Record<string, string>
- Required:
false
- Description: Additional HTML attributes to apply to the select input element.
Slots
beforeLabel
- Props:
ExposedData
- Description: Content displayed before the label text.
label
- Props:
ExposedData
- Description: The main label content. Defaults to the
label
prop if not provided.
required
- Props:
ExposedData
- Description: Content displayed for the required indicator. Defaults to
*
if not provided.
afterLabel
- Props:
ExposedData
- Description: Content displayed after the label text.
beforeInput
- Props:
ExposedData
- Description: Content displayed before the select field.
placeholder
- Props:
{ isDropdownOpen: boolean, placeholder: string }
- Description: Custom placeholder content. Defaults to the
placeholder
prop.
selector
- Props:
{ isDropdownOpen: boolean, activeOptions: QuesoSelectMultipleOptions }
- Description: Custom selector content showing the selected option(s). Defaults to displaying the selected option labels.
icon
- Props:
{ isDropdownOpen: boolean }
- Description: Custom dropdown icon. Defaults to "+".
item
- Props:
{ index: number, value: string, label: string, data: any }
- Description: Custom dropdown item content. Defaults to displaying the option label.
afterInput
- Props:
ExposedData
- Description: Content displayed after the select field.
error
- Props:
ExposedData
- Description: Content displayed when the field has an error state.
Examples
Basic TypeScript Support
vue
<template>
<queso-select-multiple
name="skills"
label="Skills"
:options="skillOptions"
placeholder="Choose skills"
v-model="selectedSkills"
/>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { QuesoSelectMultiple } from "@allomambo/queso";
import type {
QuesoSelectMultipleModel,
QuesoSelectMultipleOptions,
} from "@allomambo/queso";
const selectedSkills = ref<QuesoSelectMultipleModel>([]);
const skillOptions: QuesoSelectMultipleOptions = [
{ label: "JavaScript", value: "js" },
{ label: "TypeScript", value: "ts" },
{ label: "Vue.js", value: "vue" },
{ label: "React", value: "react" },
{ label: "Node.js", value: "node" },
];
</script>
html
<div class="queso-field">
<div class="queso-field__label">
<span class="queso-field__label__text">Skills</span>
</div>
<div class="queso-field__input">
<div class="queso-dropdown queso-select">
<div class="queso-dropdown__selector">
<span class="queso-dropdown__selector__placeholder"
>Choose skills</span
>
<span class="queso-dropdown__selector__icon">+</span>
</div>
<select
class="queso-select__select-native"
id="skills"
name="skills"
multiple
>
<option></option>
<option value="js">JavaScript</option>
<option value="ts">TypeScript</option>
<option value="vue">Vue.js</option>
<option value="react">React</option>
<option value="node">Node.js</option>
</select>
</div>
</div>
</div>
Custom Selector with Multiple Options
vue
<template>
<queso-select-multiple
name="categories"
label="Product Categories"
:options="categoryOptions"
placeholder="Select categories"
v-model="selectedCategories"
>
<template #selector="{ isDropdownOpen, activeOptions }">
<div class="custom-selector">
<span v-if="activeOptions.length > 0" class="selected-options">
{{ activeOptions.map((opt) => opt.label).join(", ") }}
</span>
<span v-else class="placeholder-text">Select categories</span>
</div>
</template>
<template #icon="{ isDropdownOpen }">
<span class="custom-icon">{{ isDropdownOpen ? "−" : "+" }}</span>
</template>
</queso-select-multiple>
</template>
<script setup>
import { ref } from "vue";
import { QuesoSelectMultiple } from "@allomambo/queso";
const selectedCategories = ref([]);
const categoryOptions = [
{ label: "Electronics", value: "electronics" },
{ label: "Clothing", value: "clothing" },
{ label: "Books", value: "books" },
{ label: "Home & Garden", value: "home" },
];
</script>
html
<div class="queso-field">
<div class="queso-field__label">
<span class="queso-field__label__text">Product Categories</span>
</div>
<div class="queso-field__input">
<div class="queso-dropdown queso-select">
<div class="queso-dropdown__selector">
<div class="custom-selector">
<span class="placeholder-text">Select categories</span>
</div>
<span class="custom-icon">+</span>
</div>
<select
class="queso-select__select-native"
id="categories"
name="categories"
multiple
>
<option></option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="books">Books</option>
<option value="home">Home & Garden</option>
</select>
</div>
</div>
</div>
With Extra Attributes
vue
<template>
<queso-select-multiple
name="permissions"
label="User Permissions"
:options="permissionOptions"
placeholder="Select permissions"
v-model="selectedPermissions"
:extra-attributes="{
'data-testid': 'permissions-select',
'aria-describedby': 'permissions-help',
}"
/>
<div id="permissions-help" class="help-text">
Select the permissions you want to grant to this user
</div>
</template>
<script setup>
import { ref } from "vue";
import { QuesoSelectMultiple } from "@allomambo/queso";
const selectedPermissions = ref([]);
const permissionOptions = [
{ label: "Read", value: "read" },
{ label: "Write", value: "write" },
{ label: "Delete", value: "delete" },
{ label: "Admin", value: "admin" },
];
</script>
html
<div class="queso-field">
<div class="queso-field__label">
<span class="queso-field__label__text">User Permissions</span>
</div>
<div class="queso-field__input">
<div class="queso-dropdown queso-select">
<div class="queso-dropdown__selector">
<span class="queso-dropdown__selector__placeholder"
>Select permissions</span
>
<span class="queso-dropdown__selector__icon">+</span>
</div>
<select
class="queso-select__select-native"
id="permissions"
name="permissions"
multiple
data-testid="permissions-select"
aria-describedby="permissions-help"
>
<option></option>
<option value="read">Read</option>
<option value="write">Write</option>
<option value="delete">Delete</option>
<option value="admin">Admin</option>
</select>
</div>
</div>
</div>
<div id="permissions-help" class="help-text">
Select the permissions you want to grant to this user
</div>
Read-only Field
vue
<template>
<queso-select-multiple
name="roles"
label="User Roles"
:options="roleOptions"
placeholder="Select roles"
is-read-only
v-model="userRoles"
/>
</template>
<script setup>
import { ref } from "vue";
import { QuesoSelectMultiple } from "@allomambo/queso";
const userRoles = ref(["admin", "moderator"]);
const roleOptions = [
{ label: "User", value: "user" },
{ label: "Moderator", value: "moderator" },
{ label: "Admin", value: "admin" },
{ label: "Super Admin", value: "super-admin" },
];
</script>
html
<div class="queso-field is-read-only">
<div class="queso-field__label">
<span class="queso-field__label__text">User Roles</span>
</div>
<div class="queso-field__input">
<div class="queso-select__read-only">
<span class="queso-select__read-only__label">Admin, Moderator</span>
</div>
</div>
</div>
Behavior
- Two-way Data Binding: Uses Vue 3's
defineModel
for seamlessv-model
integration - Form Integration: Designed to work seamlessly with HTML forms
- Multiple Selection: Multiple options can be selected simultaneously
- Read-only Mode: When
is-read-only
is true, displays the selected values as non-interactive text - Customizable Appearance: Slots for customizing dropdown selector, icon, and item appearance
- Dropdown Integration: Built on top of
QuesoDropdown
component for enhanced functionality
Accessibility
- Label Association: Uses proper
label
element withfor
attribute - Required Indicator: Displays visual indicator for required fields
- Error States: Provides clear error messaging and styling
- Keyboard Navigation: Full keyboard accessibility support
- Screen Reader Support: Proper ARIA attributes and semantic structure
- State Management: Tracks hover and focus states for accessibility
- Select Semantics: Proper select semantics with native select element
CSS Classes
Field Container
.queso-field
- Main field container.queso-field.is-disabled
- Disabled state.queso-field.is-error
- Error state.queso-field.is-active
- Focused state.queso-field.is-hover
- Hover state.queso-field.is-read-only
- Read-only state
Label
.queso-field__label
- Label container.queso-field__label__text
- Label text.queso-field__label__required
- Required indicator
Select
🎨
The styles for the select component come from the QuesoSelect
component. See the CSS Classes section in QuesoSelect for detailed styling information.
Error
.queso-field__error
- Error message container
Type Declaration
typescript
export interface ExposedData {
fieldID: string;
fieldName: string;
isRequired: boolean;
isDisabled: boolean;
isReadOnly: boolean;
isError: boolean;
isActive: boolean;
isHover: boolean;
}
export type QuesoSelectMultipleOption = QuesoDropdownOption;
export type QuesoSelectMultipleOptions = QuesoDropdownOptions;
export type QuesoSelectMultipleModel = QuesoDropdownModel;
export interface QuesoSelectMultipleProps {
name: string;
label?: string;
id?: string;
options: QuesoSelectMultipleOptions;
placeholder?: string;
isRequired?: boolean;
isDisabled?: boolean;
isReadOnly?: boolean;
isError?: boolean;
extraAttributes?: Record<string, string>;
}