Components
Multiselect
Displays a list of options for the user to pick from
Source Code
- Install the Vue 3 Multiselect package
yarn add @vueform/multiselect
Copy the following code into your project.
<template>
<div class="w-full">
<UILabel
:for="inputId"
v-if="formLabel"
class="mb-1.5"
:class="[disabled && 'text-muted-foreground', errorMessage && 'text-destructive']"
>{{ formLabel }} <span v-if="required" class="text-destructive">*</span></UILabel
>
<Multiselect
:attrs="{
id: inputId,
}"
:disabled="disabled"
v-bind="$attrs"
:id="inputId"
v-model="localModel"
:classes="{
containerActive: 'ring-2 ring-ring ring-offset-2 ring-offset-background transition',
}"
>
<template v-for="(_, name) in $slots" v-slot:[name]="scope">
<slot :name="name" v-bind="scope || {}"></slot>
</template>
<template #clear="{ clear }">
<button @click="clear" class="mr-2 flex items-center justify-center">
<Icon name="heroicons:x-mark" size="16" class="text-muted-foreground" />
</button>
</template>
</Multiselect>
<slot :errorMessage="errorMessage" name="hint">
<TransitionSlide :offset="[0, -10]">
<p class="mt-1.5 text-xs text-muted-foreground" v-if="hint && !errorMessage">
{{ hint }}
</p>
</TransitionSlide>
</slot>
<p v-if="errorMessage" class="mt-1.5 text-xs text-destructive">
<TransitionSlide :offset="[0, -10]">
<span v-if="errorMessage">
{{ errorMessage }}
</span>
</TransitionSlide>
</p>
</div>
</template>
<script setup lang="ts">
import Multiselect from "@vueform/multiselect";
interface Props
extends /* @vue-ignore */ Partial<Omit<InstanceType<typeof Multiselect>, "$emit">> {}
const props = defineProps<
{
modelValue?: any;
formLabel?: string;
required?: boolean;
id?: string;
errorMessage?: string;
hint?: string;
disabled?: boolean;
} & Props
>();
const emit = defineEmits([
"paste",
"open",
"close",
"select",
"deselect",
"input",
"search-change",
"tag",
"option",
"update:modelValue",
"change",
"clear",
"keydown",
"keyup",
"max",
"create",
]);
defineOptions({ inheritAttrs: false });
const localModel = computed({
get() {
return props.modelValue;
},
set(v) {
emit("update:modelValue", v);
},
});
// Get the id of the input from the label or name
const inputId = computed(() => props.id || `ms-${Math.random().toString(36).substring(2, 9)}`);
</script>
<style src="@vueform/multiselect/themes/default.css"></style>
<style>
:root {
--ms-font-size: theme("fontSize.sm");
--ms-line-height: 1.375;
--ms-bg: theme("colors.background");
--ms-bg-disabled: transparent;
--ms-border-color: theme("colors.input");
--ms-border-width: 1px;
--ms-border-color-active: theme("colors.input");
--ms-border-width-active: 1px;
--ms-radius: theme("borderRadius.md");
--ms-py: theme("padding.2");
--ms-px: theme("padding.3");
--ms-ring-width: 0px;
--ms-ring-color: theme("colors.ring");
--ms-placeholder-color: theme("colors.muted.foreground");
--ms-max-height: theme("height.52");
--ms-spinner-color: theme("colors.muted.foreground");
--ms-caret-color: theme("colors.muted.foreground");
--ms-clear-color: theme("colors.muted.foreground");
--ms-clear-color-hover: theme("colors.primary.DEFAULT");
--ms-tag-font-size: theme("fontSize.sm");
--ms-tag-line-height: 1.25rem;
--ms-tag-font-weight: 500;
--ms-tag-bg: theme("colors.primary.DEFAULT");
--ms-tag-bg-disabled: transparent;
--ms-tag-color: theme("colors.primary.foreground");
--ms-tag-color-disabled: theme("colors.muted.foreground");
--ms-tag-radius: theme("borderRadius.DEFAULT");
--ms-tag-py: theme("padding[0.5]");
--ms-dropdown-bg: theme("colors.background");
--ms-dropdown-border-color: theme("colors.border");
--ms-dropdown-border-width: 1px;
--ms-dropdown-radius: theme("borderRadius.md");
--ms-group-label-bg: theme("colors.muted.DEFAULT");
--ms-group-label-color: theme("colors.muted.foreground");
--ms-group-label-bg-pointed: theme("colors.primary.DEFAULT");
--ms-group-label-color-pointed: theme("colors.primary.foreground");
--ms-group-label-bg-disabled: theme("colors.muted.DEFAULT / 50%");
--ms-group-label-color-disabled: theme("colors.muted.foreground / 50%");
--ms-group-label-bg-selected: theme("colors.primary.DEFAULT");
--ms-group-label-color-selected: theme("colors.primary.foreground");
--ms-group-label-bg-selected-pointed: theme("colors.primary.DEFAULT");
--ms-group-label-color-selected-pointed: theme("colors.primary.foreground");
--ms-group-label-bg-selected-disabled: theme("colors.muted.DEFAULT / 50%");
--ms-group-label-color-selected-disabled: theme("colors.muted.foreground / 50%");
--ms-option-font-size: theme("fontSize.sm");
--ms-option-bg-pointed: theme("colors.primary.DEFAULT");
--ms-option-color-pointed: theme("colors.primary.foreground");
--ms-option-bg-selected: theme("colors.primary.DEFAULT");
--ms-option-color-selected: theme("colors.primary.foreground");
--ms-option-bg-disabled: transparent;
--ms-option-color-disabled: theme("colors.muted.foreground / 50%");
--ms-option-bg-selected-pointed: theme("colors.primary.DEFAULT");
--ms-option-color-selected-pointed: theme("colors.primary.foreground");
--ms-option-bg-selected-disabled: theme("colors.muted.DEFAULT");
--ms-option-color-selected-disabled: theme("colors.muted.foreground");
--ms-empty-color: theme("colors.muted.foreground");
}
</style>
Usage
Group
Table of contents