Appearance
ComboBox Component Demo
This page demonstrates the ComboBox component with various configurations and examples.
Basic ComboBox
A simple combobox where users can select from options or type their own value.
Code Example
vue
<template>
<OComboBox
v-model="selectedValue"
:items="items"
placeholder="Select or type your own..."
/>
</template>
<script setup>
import { ref } from 'vue';
const selectedValue = ref(null);
const items = ref([
{ text: 'Apple', value: 'apple' },
{ text: 'Banana', value: 'banana' },
{ text: 'Cherry', value: 'cherry' },
{ text: 'Date', value: 'date' },
{ text: 'Elderberry', value: 'elderberry' },
]);
</script>Demo
Selected: None
💡 Tip: Type anything and press Enter or click outside to create a custom value
Tag Input (Multiple Selection)
Create custom tags or select from suggestions.
Code Example
vue
<template>
<OComboBox
v-model="selectedTags"
:items="suggestions"
:multiple="true"
placeholder="Type tags and press Enter..."
/>
</template>
<script setup>
import { ref } from 'vue';
const selectedTags = ref([]);
const suggestions = ref([
{ text: 'JavaScript', value: 'js' },
{ text: 'TypeScript', value: 'ts' },
{ text: 'Python', value: 'py' },
{ text: 'Java', value: 'java' },
{ text: 'C++', value: 'cpp' },
]);
</script>Demo
Selected: None
💡 Tip: Type any text and press Enter to create custom tags
Email Address Input
Perfect for email input with suggestions and custom entries.
Code Example
vue
<template>
<OComboBox
v-model="emails"
:items="suggestions"
:multiple="true"
placeholder="Type email addresses..."
/>
</template>
<script setup>
import { ref } from 'vue';
const emails = ref([]);
const suggestions = ref([
{ text: 'john@example.com', value: 'john@example.com' },
{ text: 'jane@example.com', value: 'jane@example.com' },
{ text: 'bob@example.com', value: 'bob@example.com' },
]);
</script>Demo
Emails: None
Create Event Handling
Track when custom items are created.
Code Example
vue
<template>
<OComboBox
v-model="selectedValues"
:items="items"
:multiple="true"
placeholder="Add colors..."
@create="handleCreate"
/>
<div v-if="createdItems.length > 0">
<h4>Recently Created:</h4>
<ul>
<li v-for="(created, index) in createdItems" :key="index">
{{ created.value }} at {{ created.timestamp }}
</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue';
const selectedValues = ref([]);
const items = ref([
{ text: 'Red', value: 'red' },
{ text: 'Blue', value: 'blue' },
{ text: 'Green', value: 'green' },
]);
const createdItems = ref([]);
const handleCreate = (item, value) => {
createdItems.value.push({
item,
value,
timestamp: new Date().toLocaleTimeString()
});
};
</script>Demo
Selected: None
Clearable Input
ComboBox with a clear button.
Code Example
vue
<template>
<OComboBox
v-model="selectedValue"
:items="items"
:clearable="true"
placeholder="Select or type..."
/>
</template>
<script setup>
import { ref } from 'vue';
const selectedValue = ref('custom-value');
const items = ref([
{ text: 'Option 1', value: 'opt1' },
{ text: 'Option 2', value: 'opt2' },
{ text: 'Option 3', value: 'opt3' },
]);
</script>Demo
Selected: custom-value
Selected Items on Top
Keep chosen options at the top of the list.
Code Example
vue
<template>
<OComboBox
v-model="selectedFrameworks"
:items="frameworks"
:multiple="true"
:selected-on-top="true"
placeholder="Select frameworks..."
/>
</template>
<script setup>
import { ref } from 'vue';
const selectedFrameworks = ref(['vue', 'react']);
const frameworks = ref([
{ text: 'React', value: 'react' },
{ text: 'Vue', value: 'vue' },
{ text: 'Angular', value: 'angular' },
{ text: 'Svelte', value: 'svelte' },
{ text: 'Ember', value: 'ember' },
{ text: 'Solid', value: 'solid' },
]);
</script>Demo
Selected: vue, react
Custom Filter Function
Search across multiple properties.
Code Example
vue
<template>
<OComboBox
v-model="selectedProducts"
:items="products"
:multiple="true"
:filter-function="customFilter"
placeholder="Search by name, category, or brand..."
/>
</template>
<script setup>
import { ref } from 'vue';
const selectedProducts = ref([]);
const products = ref([
{ text: 'Apple MacBook Pro', value: 'mbp', category: 'laptop', brand: 'Apple' },
{ text: 'Apple iPhone 15', value: 'iphone15', category: 'phone', brand: 'Apple' },
{ text: 'Samsung Galaxy S24', value: 's24', category: 'phone', brand: 'Samsung' },
{ text: 'Dell XPS 13', value: 'xps', category: 'laptop', brand: 'Dell' },
{ text: 'Microsoft Surface Pro', value: 'surface', category: 'tablet', brand: 'Microsoft' },
]);
const customFilter = (item, searchText) => {
const text = item.text.toLowerCase();
const category = item.category.toLowerCase();
const brand = item.brand.toLowerCase();
const search = searchText.toLowerCase();
return text.includes(search) || category.includes(search) || brand.includes(search);
};
</script>Demo
Selected: None
💡 Try searching "laptop", "Apple", or "phone"
Disabled State
ComboBox in disabled state.
Code Example
vue
<template>
<OComboBox
v-model="selectedValue"
:items="items"
:disabled="true"
placeholder="This field is disabled"
/>
</template>
<script setup>
import { ref } from 'vue';
const selectedValue = ref('custom-disabled-value');
const items = ref([
{ text: 'Option 1', value: 'opt1' },
{ text: 'Option 2', value: 'opt2' },
]);
</script>Demo
Selected: custom-disabled-value
Readonly State
ComboBox in readonly state.
Code Example
vue
<template>
<OComboBox
v-model="selectedValue"
:items="items"
:readonly="true"
placeholder="This field is readonly"
/>
</template>
<script setup>
import { ref } from 'vue';
const selectedValue = ref('readonly-custom');
const items = ref([
{ text: 'Value 1', value: 'val1' },
{ text: 'Value 2', value: 'val2' },
]);
</script>Demo
Selected: readonly-custom
Different Placements
ComboBox with various placement options.
Code Example
vue
<template>
<div class="placement-examples">
<OComboBox
v-model="selectedValue"
:items="items"
placement="bottom"
placeholder="Bottom (default)"
/>
<OComboBox
v-model="selectedValue"
:items="items"
placement="top"
placeholder="Top"
/>
</div>
</template>
<script setup>
import { ref } from 'vue';
const selectedValue = ref(null);
const items = ref([
{ text: 'Option 1', value: 'opt1' },
{ text: 'Option 2', value: 'opt2' },
{ text: 'Option 3', value: 'opt3' },
]);
</script>
<style scoped>
.placement-examples {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
padding: 4rem 2rem;
}
</style>Demo
Form Integration
ComboBox integrated into a form with validation.
Code Example
vue
<template>
<form @submit.prevent="submitForm" class="form-example">
<div class="form-group">
<label>Username</label>
<OComboBox
v-model="formData.username"
:items="usernameSuggestions"
placeholder="Select or type username..."
/>
<span v-if="formErrors.username" class="error">{{ formErrors.username }}</span>
</div>
<div class="form-group">
<label>Skills</label>
<OComboBox
v-model="formData.skills"
:items="skillsSuggestions"
:multiple="true"
placeholder="Add your skills..."
/>
<span v-if="formErrors.skills" class="error">{{ formErrors.skills }}</span>
</div>
<div class="form-group">
<label>Notes/Tags</label>
<OComboBox
v-model="formData.notes"
:items="[]"
:multiple="true"
placeholder="Type notes or tags..."
/>
<span v-if="formErrors.notes" class="error">{{ formErrors.notes }}</span>
</div>
<div class="form-actions">
<button type="submit" class="submit-btn">Submit Form</button>
<button type="button" @click="validateForm" class="validate-btn">Validate Only</button>
</div>
</form>
</template>
<script setup>
import { reactive, ref } from 'vue';
const formData = reactive({
username: null,
skills: [],
notes: [],
});
const formErrors = reactive({
username: '',
skills: '',
notes: '',
});
const usernameSuggestions = ref([
{ text: 'john_doe', value: 'john_doe' },
{ text: 'jane_smith', value: 'jane_smith' },
{ text: 'bob_wilson', value: 'bob_wilson' },
]);
const skillsSuggestions = ref([
{ text: 'JavaScript', value: 'js' },
{ text: 'TypeScript', value: 'ts' },
{ text: 'Vue.js', value: 'vue' },
{ text: 'React', value: 'react' },
{ text: 'Node.js', value: 'node' },
]);
const validateForm = () => {
formErrors.username = !formData.username ? 'Username is required' : '';
formErrors.skills = formData.skills.length === 0 ? 'At least one skill is required' : '';
formErrors.notes = formData.notes.length === 0 ? 'At least one note is required' : '';
};
const submitForm = () => {
validateForm();
if (!formErrors.username && !formErrors.skills && !formErrors.notes) {
console.log('Form submitted:', formData);
alert('Form submitted successfully!');
}
};
</script>
<style scoped>
.form-example {
max-width: 500px;
padding: 1.5rem;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
background: #fafafa;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
color: #374151;
}
.error {
color: #ef4444;
font-size: 0.875rem;
margin-top: 0.25rem;
display: block;
}
.form-actions {
display: flex;
gap: 0.75rem;
margin-top: 1.5rem;
}
.submit-btn, .validate-btn {
padding: 0.625rem 1.25rem;
border: none;
border-radius: 0.375rem;
cursor: pointer;
font-weight: 500;
transition: all 0.2s;
}
.submit-btn {
background: #3b82f6;
color: white;
}
.submit-btn:hover {
background: #2563eb;
}
.validate-btn {
background: #6b7280;
color: white;
}
.validate-btn:hover {
background: #4b5563;
}
</style>