Skip to content
Last update: June 24, 2025

VcMultivalue Component

The VcMultivalue component is a versatile input that allows users to select or enter multiple values. It supports both dropdown selection from predefined options and manual text entry, making it perfect for tags, multi-select, and other use cases that require collecting multiple values.

Storybook

VcMultivalue Storybook

Basic Usage

<template>
  <VcMultivalue
    v-model="selectedValues"
    label="Categories"
    placeholder="Select categories"
    :options="options"
    option-value="id"
    option-label="title"
    multivalue
  />
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import { VcMultivalue } from '@vc-shell/framework';

const selectedValues = ref([]);
const options = [
  { id: '1', title: 'Electronics' },
  { id: '2', title: 'Clothing' },
  { id: '3', title: 'Home & Garden' },
  { id: '4', title: 'Books' },
  { id: '5', title: 'Toys' }
];
</script>

Props

Prop Type Default Description
modelValue any[] [] Array of selected values
placeholder string undefined Placeholder text for the input field
type 'text' | 'number' | 'integer' 'text' Input type for manual entry
label string undefined Label text for the field
tooltip string undefined Tooltip text for additional information
name string 'Field' Name attribute for the field
hint string undefined Helper text displayed below the field
options any[] [] Available options for selection
optionValue string 'id' Property name to use as the option value
optionLabel string 'title' Property name to use as the option label
multivalue boolean false Enables multiple value selection mode
error boolean false Indicates an error state
errorMessage string undefined Error message to display
required boolean false Makes the field required
disabled boolean false Disables the field
loading boolean false Shows a loading indicator
multilanguage boolean false Enable multilanguage support for the label
currentLanguage string undefined Current language code for multilanguage support

Events

Event Payload Description
update:model-value any[] Emitted when selected values change
close - Emitted when the dropdown is closed
search string Emitted when searching in the dropdown

Slots

Slot Props Description
option { item } Custom template for dropdown options
selected-item { value, item, remove } Custom template for selected values
error - Custom error message content
hint - Custom hint content

CSS Variables

:root {
  /* Base styles */
  --multivalue-height: 36px;                            /* Height of the multivalue field */
  --multivalue-border-radius: 4px;                      /* Border radius of the input field */
  --multivalue-border-color: var(--neutrals-300);       /* Border color in normal state */
  --multivalue-border-color-error: var(--danger-100);   /* Border color in error state */
  --multivalue-background-color: var(--additional-50);  /* Background color of the multivalue field */
  --multivalue-placeholder-color: var(--neutrals-400);  /* Color of placeholder text */
  --multivalue-text-color: var(--neutrals-800);         /* Color of input text */
  --multivalue-padding: 10px;                           /* Internal padding of the field */

  /* Dropdown & Select styles */
  --multivalue-select-border-radius: 4px;                /* Border radius of dropdown */
  --multivalue-select-border-color: var(--neutrals-200); /* Border color of dropdown */
  --multivalue-select-border-color-error: var(--danger-500); /* Border color of dropdown in error state */
  --multivalue-select-background-color: var(--additional-50); /* Background color of dropdown */
  --multivalue-select-placeholder-color: var(--neutrals-400); /* Color of placeholder text in dropdown */
  --multivalue-select-chevron-color: var(--primary-500);      /* Color of dropdown arrow icon */
  --multivalue-select-chevron-color-hover: var(--primary-600); /* Color of dropdown arrow icon on hover */

  /* Item styles */
  --multivalue-search-border-color: var(--secondary-200);      /* Border color of search field in dropdown */
  --multivalue-item-hover-background-color: var(--accent-100); /* Background color of dropdown item on hover */
  --multivalue-hint-color: var(--danger-500);                  /* Color of hint/error text */
  --multivalue-field-value-background-color: var(--additional-50); /* Background color of selected value tags */
  --multivalue-field-value-border-color: var(--secondary-200);     /* Border color of selected value tags */
  --multivalue-clear-icon-color: var(--primary-500);          /* Color of clear icon in selected value tags */

  /* Disabled state */
  --multivalue-select-background-color-disabled: var(--neutrals-50); /* Background color when disabled */
  --multivalue-disabled-text-color: var(--neutrals-500);             /* Text color when disabled */
  --multivalue-disabled-background-color: var(--neutrals-200);       /* Background color when disabled */
}

Examples

Basic Multiple Selection

<template>
  <VcMultivalue
    v-model="selectedValues"
    label="Categories"
    placeholder="Select categories"
    :options="categories"
    option-value="id"
    option-label="name"
    multivalue
  />

  <div class="tw-mt-4">
    <p>Selected categories: {{ selectedValues.length }}</p>
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import { VcMultivalue } from '@vc-shell/framework';

const selectedValues = ref([]);
const categories = [
  { id: '1', name: 'Electronics' },
  { id: '2', name: 'Clothing' },
  { id: '3', name: 'Home & Garden' },
  { id: '4', name: 'Books' },
  { id: '5', name: 'Toys' }
];
</script>

Manual Text Entry Mode

<template>
  <VcMultivalue
    v-model="tags"
    label="Tags"
    placeholder="Add tags (press Enter after each tag)"
    hint="Enter keywords that describe your product"
    :multivalue="false"
  />

  <div class="tw-mt-4 tw-flex tw-flex-wrap tw-gap-1">
    <div 
      v-for="(tag, index) in tags" 
      :key="index"
      class="tw-px-2 tw-py-1 tw-bg-[var(--primary-100)] tw-text-[var(--primary-800)] tw-rounded"
    >
      {{ tag }}
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import { VcMultivalue } from '@vc-shell/framework';

const tags = ref([]);
</script>

With Validation

<template>
  <VcForm @submit.prevent="validateForm">
    <VcMultivalue
      v-model="selectedItems"
      label="Required Field"
      placeholder="Select at least one item"
      :options="items"
      option-value="id"
      option-label="name"
      multivalue
      required
      :error="hasError"
      :errorMessage="errorMessage"
    />

    <div class="tw-mt-4">
      <VcButton type="submit">
        Validate
      </VcButton>
    </div>
  </VcForm>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import { VcMultivalue, VcForm, VcButton } from '@vc-shell/framework';

const selectedItems = ref([]);
const hasError = ref(false);
const errorMessage = ref('');

const items = [
  { id: '1', name: 'Item 1' },
  { id: '2', name: 'Item 2' },
  { id: '3', name: 'Item 3' },
  { id: '4', name: 'Item 4' },
  { id: '5', name: 'Item 5' }
];

function validateForm() {
  if (selectedItems.value.length === 0) {
    hasError.value = true;
    errorMessage.value = 'Please select at least one item';
  } else {
    hasError.value = false;
    errorMessage.value = '';
    console.log('Form is valid!', selectedItems.value);
  }
}
</script>

Custom Item Templates

<template>
  <VcMultivalue
    v-model="selectedUsers"
    label="Assign Users"
    placeholder="Select users to assign"
    :options="users"
    option-value="id"
    option-label="name"
    multivalue
  >
    <template #option="{ item }">
      <div class="tw-flex tw-items-center">
        <div 
          class="tw-w-6 tw-h-6 tw-rounded-full tw-flex tw-items-center tw-justify-center tw-bg-[var(--primary-100)] tw-text-[var(--primary-800)] tw-mr-2"
        >
          {{ item.name.charAt(0) }}
        </div>
        <div>
          <div class="tw-font-medium">{{ item.name }}</div>
          <div class="tw-text-xs tw-text-[var(--neutrals-500)]">{{ item.email }}</div>
        </div>
      </div>
    </template>

    <template #selected-item="{ item, remove }">
      <div class="tw-flex tw-items-center">
        <div 
          class="tw-w-5 tw-h-5 tw-rounded-full tw-flex tw-items-center tw-justify-center tw-bg-[var(--primary-100)] tw-text-[var(--primary-800)] tw-mr-1"
        >
          {{ item.name.charAt(0) }}
        </div>
        <span class="tw-mr-1">{{ item.name }}</span>
        <VcIcon
          icon="material-close"
          size="xs"
          class="tw-cursor-pointer"
          @click="remove"
        />
      </div>
    </template>
  </VcMultivalue>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import { VcMultivalue, VcIcon } from '@vc-shell/framework';

const selectedUsers = ref([]);
const users = [
  { id: '1', name: 'John Doe', email: '[email protected]' },
  { id: '2', name: 'Jane Smith', email: '[email protected]' },
  { id: '3', name: 'Michael Brown', email: '[email protected]' },
  { id: '4', name: 'Sarah Johnson', email: '[email protected]' },
  { id: '5', name: 'David Williams', email: '[email protected]' }
];
</script>

Numeric Values

<template>
  <VcMultivalue
    v-model="quantities"
    label="Quantities"
    placeholder="Add quantities (press Enter after each value)"
    type="number"
    :multivalue="false"
    hint="Enter numeric values only"
  />
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import { VcMultivalue } from '@vc-shell/framework';

const quantities = ref([]);
</script>

Loading State

<template>
  <VcMultivalue
    v-model="selectedCategories"
    label="Categories"
    placeholder="Loading categories..."
    :options="categories"
    option-value="id"
    option-label="name"
    multivalue
    :loading="isLoading"
  />

  <div class="tw-mt-4">
    <VcButton @click="loadCategories">
      {{ isLoading ? 'Loading...' : 'Reload Categories' }}
    </VcButton>
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import { VcMultivalue, VcButton } from '@vc-shell/framework';

const selectedCategories = ref([]);
const categories = ref([]);
const isLoading = ref(true);

// Simulate API call
function loadCategories() {
  isLoading.value = true;
  categories.value = [];

  setTimeout(() => {
    categories.value = [
      { id: '1', name: 'Electronics' },
      { id: '2', name: 'Clothing' },
      { id: '3', name: 'Home & Garden' },
      { id: '4', name: 'Books' },
      { id: '5', name: 'Toys' }
    ];
    isLoading.value = false;
  }, 1500);
}

// Load categories on mount
loadCategories();
</script>

Product Form with Tags

<template>
  <VcForm @submit.prevent="saveProduct">
    <div class="tw-space-y-4">
      <VcInput
        v-model="product.name"
        label="Product Name"
        required
      />

      <VcMultivalue
        v-model="product.categories"
        label="Categories"
        placeholder="Select product categories"
        :options="categories"
        option-value="id"
        option-label="name"
        multivalue
        required
      />

      <VcMultivalue
        v-model="product.tags"
        label="Tags"
        placeholder="Add search tags (press Enter after each tag)"
        :multivalue="false"
        hint="Add keywords to help customers find your product"
      />

      <div class="tw-mt-6 tw-flex tw-justify-end">
        <VcButton type="submit" variant="primary">
          Save Product
        </VcButton>
      </div>
    </div>
  </VcForm>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import { VcMultivalue, VcForm, VcInput, VcButton } from '@vc-shell/framework';

const product = reactive({
  name: '',
  categories: [],
  tags: []
});

const categories = [
  { id: '1', name: 'Electronics' },
  { id: '2', name: 'Clothing' },
  { id: '3', name: 'Home & Garden' },
  { id: '4', name: 'Books' },
  { id: '5', name: 'Toys' }
];

function saveProduct() {
  console.log('Product saved:', product);
  // Implement API call to save product
}
</script>