Last update:
June 24, 2025
VcInputDropdown Component¶
The VcInputDropdown
component is a versatile input component that combines an input field with a dropdown selection. It's ideal for scenarios where users need to both input a value and select a category, unit, or format for that value.
Storybook¶
Basic Usage¶
<template>
<VcInputDropdown
v-model="inputValue"
v-model:option="selectedOption"
:options="options"
label="Input with Dropdown"
placeholder="Enter value"
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { VcInputDropdown } from '@vc-shell/framework';
const inputValue = ref('100');
const selectedOption = ref('Option 1');
const options = ['Option 1', 'Option 2', 'Option 3', 'Option 4', 'Option 5'];
</script>
Props¶
Prop | Type | Default | Description |
---|---|---|---|
modelValue |
string \| number \| Date \| null \| undefined |
- | The value of the input field (v-model binding) |
option |
unknown |
- | Default selected dropdown option (v-model:option binding) |
options |
unknown[] |
[] |
Array of options to display in the dropdown |
optionValue |
string \| ((option: unknown) => string) |
'id' |
Property or function to extract option value |
optionLabel |
string \| ((option: unknown) => string) |
'title' |
Property or function to extract option label |
label |
string |
- | Label text for the input |
placeholder |
string |
- | Placeholder text when no input is entered |
hint |
string |
- | Hint text to display below the input |
clearable |
boolean |
false |
Whether the input field can be cleared |
prefix |
string |
- | Text to display before the input value |
suffix |
string |
- | Text to display after the input value |
name |
string |
'Field' |
HTML name attribute for the input field |
loading |
boolean |
false |
Shows a loading indicator |
debounce |
string \| number |
0 |
Debounce time in milliseconds for input changes |
disabled |
boolean |
false |
Disables the component |
autofocus |
boolean |
false |
Focuses the input field on component mount |
error |
boolean |
false |
Shows the component in error state |
errorMessage |
string |
- | Error message to display when in error state |
maxlength |
string \| number |
- | Maximum character length for the input field |
tooltip |
string |
- | Tooltip text to show on hover |
required |
boolean |
false |
Marks the component as required (shows asterisk) |
searchable |
boolean |
false |
Enables search functionality in the dropdown |
inputType |
string |
'text' |
Type of the input field (text, number, email, etc.) |
Events¶
Event | Parameters | Description |
---|---|---|
update:modelValue |
(value: string \| number \| Date \| null \| undefined) => void |
Emitted when the input value changes |
update:option |
(value: unknown) => void |
Emitted when the selected option changes |
change |
(value: unknown) => void |
Emitted when input value changes |
blur |
(event: Event) => void |
Emitted when the input loses focus |
Slots¶
Slot | Props | Description |
---|---|---|
button |
{ toggleHandler: () => void } |
Custom dropdown toggle button |
control |
{ placeholder, focused, modelValue, emitValue } |
Custom input control |
append-inner |
- | Content to append inside the input field |
prepend-inner |
- | Content to prepend inside the input field |
append |
- | Content to append outside the input field |
prepend |
- | Content to prepend outside the input field |
CSS Variables¶
The component uses the following CSS variables for styling:
:root {
--input-dropdown-toggle-color: var(--primary-500); /* Color of the dropdown toggle button */
}
Examples¶
Basic Dropdown¶
<template>
<VcInputDropdown
v-model="inputValue"
v-model:option="selectedUnit"
:options="unitOptions"
label="Measurement"
placeholder="Enter value"
inputType="number"
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { VcInputDropdown } from '@vc-shell/framework';
const inputValue = ref(100);
const selectedUnit = ref('cm');
const unitOptions = ['mm', 'cm', 'm', 'km'];
</script>
With Object Options¶
<template>
<VcInputDropdown
v-model="price"
v-model:option="selectedCurrency"
:options="currencies"
:option-value="currency => currency.code"
:option-label="currency => currency.name"
label="Price"
placeholder="Enter price"
inputType="number"
hint="Enter the price in the selected currency"
searchable
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { VcInputDropdown } from '@vc-shell/framework';
const price = ref(1000);
const selectedCurrency = ref({ code: 'USD', symbol: '$', name: 'US Dollar' });
const currencies = [
{ code: 'USD', symbol: '$', name: 'US Dollar' },
{ code: 'EUR', symbol: '€', name: 'Euro' },
{ code: 'GBP', symbol: '£', name: 'British Pound' },
{ code: 'JPY', symbol: '¥', name: 'Japanese Yen' },
];
</script>
Custom Dropdown Button¶
<template>
<VcInputDropdown
v-model="inputValue"
v-model:option="selectedFormat"
:options="formatOptions"
:option-value="opt => opt.id"
:option-label="opt => opt.label"
label="Date"
placeholder="Enter date"
>
<template #button="{ toggleHandler }">
<button
class="tw-flex tw-items-center tw-px-2 tw-text-primary-500 tw-font-medium"
@click.stop.prevent="toggleHandler"
>
<span>{{ selectedFormat.label }}</span>
<VcIcon icon="material-keyboard_arrow_down" size="s" class="tw-ml-1" />
</button>
</template>
</VcInputDropdown>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { VcInputDropdown, VcIcon } from '@vc-shell/framework';
const inputValue = ref('31/12/2023');
const selectedFormat = ref({ id: 'DD/MM/YYYY', label: 'Day/Month/Year' });
const formatOptions = [
{ id: 'DD/MM/YYYY', label: 'Day/Month/Year' },
{ id: 'MM/DD/YYYY', label: 'Month/Day/Year' },
{ id: 'YYYY-MM-DD', label: 'ISO Format' },
];
</script>
Custom Input Control¶
<template>
<VcInputDropdown
v-model="date"
v-model:option="selectedFormat"
:options="formatOptions"
:option-value="opt => opt.id"
:option-label="opt => opt.label"
label="Date"
placeholder="Select date"
>
<template #control="{ placeholder }">
<div class="tw-flex tw-items-center tw-relative tw-w-full">
<VcButton size="xs" variety="secondary" @click="setToday">Today</VcButton>
<VcIcon icon="material-calendar_today" class="tw-text-gray-500" size="s" />
<input
v-model="date"
:placeholder="placeholder"
class="tw-w-full tw-p-2 tw-pl-8 tw-border tw-border-solid tw-border-gray-300 tw-rounded tw-text-sm tw-outline-none"
@blur="formatDate"
/>
</div>
</template>
</VcInputDropdown>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
import { VcInputDropdown, VcIcon, VcButton } from '@vc-shell/framework';
const date = ref('');
const selectedFormat = ref({ id: 'DD/MM/YYYY', label: 'Day/Month/Year' });
const formatOptions = [
{ id: 'DD/MM/YYYY', label: 'Day/Month/Year' },
{ id: 'MM/DD/YYYY', label: 'Month/Day/Year' },
{ id: 'YYYY-MM-DD', label: 'ISO Format' },
];
const formatDate = () => {
if (!date.value) return;
const today = new Date();
const day = String(today.getDate()).padStart(2, '0');
const month = String(today.getMonth() + 1).padStart(2, '0');
const year = today.getFullYear();
switch (selectedFormat.value.id) {
case 'DD/MM/YYYY':
date.value = `${day}/${month}/${year}`;
break;
case 'MM/DD/YYYY':
date.value = `${month}/${day}/${year}`;
break;
case 'YYYY-MM-DD':
date.value = `${year}-${month}-${day}`;
break;
}
};
// Format date when format changes
watch(() => selectedFormat.value, formatDate);
const setToday = () => {
formatDate();
};
</script>