Skip to content

Autocomplete Component Demo

This page demonstrates the Autocomplete component with various configurations and examples.

Basic Autocomplete

A simple autocomplete with single selection and search functionality.

Code Example

vue
<template>
  <OAutoComplete
    v-model="selectedCountry"
    :items="countries"
    placeholder="Search for a country..."
    @select="handleSelect"
    @search="handleSearch"
  />
</template>

<script setup>
import { ref } from "vue";

const selectedCountry = ref(null);
const countries = ref([
  { text: "Afghanistan", value: "af" },
  { text: "Albania", value: "al" },
  { text: "Algeria", value: "dz" },
  { text: "Argentina", value: "ar" },
  { text: "Australia", value: "au" },
  { text: "Austria", value: "at" },
  { text: "Belgium", value: "be" },
  { text: "Brazil", value: "br" },
  { text: "Canada", value: "ca" },
  { text: "China", value: "cn" },
]);

const handleSelect = (item, value) => {
  console.log("Selected:", item, value);
};

const handleSearch = (searchText) => {
  console.log("Searching for:", searchText);
};
</script>

Demo

Selected: None

Multiple Selection

Autocomplete with multiple selection and chip display.

Code Example

vue
<template>
  <OAutoComplete
    v-model="selectedFrameworks"
    :items="frameworks"
    :multiple="true"
    placeholder="Select frameworks..."
    @select="handleSelect"
    @remove="handleRemove"
  />
</template>

<script setup>
import { ref } from "vue";

const selectedFrameworks = ref([]);
const frameworks = ref([
  { text: "React", value: "react" },
  { text: "Vue", value: "vue" },
  { text: "Angular", value: "angular" },
  { text: "Svelte", value: "svelte" },
  { text: "Ember", value: "ember" },
  { text: "Backbone", value: "backbone" },
  { text: "Preact", value: "preact" },
  { text: "Alpine.js", value: "alpine" },
]);

const handleSelect = (item, value) => {
  console.log("Selected:", item, value);
};

const handleRemove = (item, value) => {
  console.log("Removed:", item, value);
};
</script>

Demo

Selected: None

Clearable Input

Autocomplete with a clear button to quickly reset the selection.

Code Example

vue
<template>
  <OAutoComplete
    v-model="selectedLanguage"
    :items="languages"
    :clearable="true"
    placeholder="Select a programming language..."
  />
</template>

<script setup>
import { ref } from "vue";

const selectedLanguage = ref("react");
const languages = ref([
  { text: "JavaScript", value: "js" },
  { text: "TypeScript", value: "ts" },
  { text: "Python", value: "py" },
  { text: "Java", value: "java" },
  { text: "C++", value: "cpp" },
  { text: "Ruby", value: "rb" },
  { text: "Go", value: "go" },
  { text: "Rust", value: "rust" },
]);
</script>

Demo

Selected: react

Selected Items on Top

Keep chosen options at the top of the list for easier management.

Code Example

vue
<template>
  <OAutoComplete
    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" },
  { text: "Qwik", value: "qwik" },
  { text: "Lit", value: "lit" },
]);
</script>

Demo

Selected: vue, react

Loading State

Display a loading spinner while fetching data.

Code Example

vue
<template>
  <OAutoComplete
    v-model="selectedValue"
    :items="items"
    :loading="isLoading"
    placeholder="Loading options..."
  />
</template>

<script setup>
import { ref } from "vue";

const selectedValue = ref(null);
const items = ref([]);
const isLoading = ref(true);

// Simulate API call
setTimeout(() => {
  isLoading.value = false;
  items.value = [
    { text: "Apple", value: "apple" },
    { text: "Banana", value: "banana" },
    { text: "Cherry", value: "cherry" },
    { text: "Date", value: "date" },
    { text: "Elderberry", value: "elderberry" },
  ];
}, 2000);
</script>

Demo

Selected: None

Perform asynchronous searches as the user types.

Code Example

vue
<template>
  <OAutoComplete
    v-model="selectedUser"
    :items="users"
    :loading="loading"
    placeholder="Search for a user (type at least 2 characters)..."
    @search="handleSearch"
  />
</template>

<script setup>
import { ref } from "vue";

const selectedUser = ref(null);
const users = ref([]);
const loading = ref(false);

const handleSearch = (searchText) => {
  if (!searchText || searchText.length < 2) {
    users.value = [];
    return;
  }

  loading.value = true;

  // Simulate API call
  setTimeout(() => {
    const allUsers = [
      { text: "John Doe", value: "john" },
      { text: "Jane Smith", value: "jane" },
      { text: "Bob Johnson", value: "bob" },
      { text: "Alice Williams", value: "alice" },
      { text: "Charlie Brown", value: "charlie" },
    ];

    users.value = allUsers.filter((user) =>
      user.text.toLowerCase().includes(searchText.toLowerCase())
    );
    loading.value = false;
  }, 500);
};
</script>

Demo

Selected: None

Custom Filter Function

Use a custom filter function to search across multiple properties.

Code Example

vue
<template>
  <OAutoComplete
    v-model="selectedProducts"
    :items="products"
    :multiple="true"
    :filter-function="customFilter"
    placeholder="Search by product name or category..."
  />
</template>

<script setup>
import { ref } from "vue";

const selectedProducts = ref([]);
const products = ref([
  { text: "Apple MacBook Pro", value: "mbp", category: "laptop" },
  { text: "Apple iPhone 15", value: "iphone15", category: "phone" },
  { text: "Apple iPad Air", value: "ipad", category: "tablet" },
  { text: "Samsung Galaxy S24", value: "s24", category: "phone" },
  { text: "Samsung Galaxy Book", value: "book", category: "laptop" },
  { text: "Dell XPS 13", value: "xps", category: "laptop" },
  { text: "Microsoft Surface Pro", value: "surface", category: "tablet" },
]);

const customFilter = (item, searchText) => {
  const text = item.text.toLowerCase();
  const category = item.category.toLowerCase();
  const search = searchText.toLowerCase();

  // Search in both text and category
  return text.includes(search) || category.includes(search);
};
</script>

Demo

Selected: None

Disabled State

Autocomplete in disabled state.

Code Example

vue
<template>
  <OAutoComplete
    v-model="selectedValue"
    :items="items"
    :disabled="true"
    placeholder="This field is disabled"
  />
</template>

<script setup>
import { ref } from "vue";

const selectedValue = ref("option1");
const items = ref([
  { text: "Option 1", value: "option1" },
  { text: "Option 2", value: "option2" },
  { text: "Option 3", value: "option3" },
]);
</script>

Demo

Selected: option1

Readonly State

Autocomplete in readonly state.

Code Example

vue
<template>
  <OAutoComplete
    v-model="selectedValue"
    :items="items"
    :readonly="true"
    placeholder="This field is readonly"
  />
</template>

<script setup>
import { ref } from "vue";

const selectedValue = ref("read");
const items = ref([
  { text: "Readonly Value", value: "read" },
  { text: "Another Value", value: "another" },
]);
</script>

Demo

Selected: read

Different Placements

Autocomplete with various placement options.

Code Example

vue
<template>
  <div class="placement-examples">
    <OAutoComplete
      v-model="selectedValue"
      :items="items"
      placement="bottom"
      placeholder="Bottom (default)"
    />

    <OAutoComplete
      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

Custom Width

Autocomplete with custom menu width.

Code Example

vue
<template>
  <div class="width-examples">
    <OAutoComplete
      v-model="selectedValue"
      :items="items"
      placeholder="Default width (matches trigger)"
    />

    <OAutoComplete
      v-model="selectedValue"
      :items="items"
      :menu-width="400"
      placeholder="Custom width (400px)"
    />
  </div>
</template>

<script setup>
import { ref } from "vue";

const selectedValue = ref(null);
const items = ref([
  { text: "Short", value: "short" },
  { text: "Medium length option", value: "medium" },
  {
    text: "Very long option text that might overflow in smaller containers",
    value: "long",
  },
]);
</script>

Demo

Selected: None

Form Integration

Autocomplete integrated into a form with validation.

Code Example

vue
<template>
  <form @submit.prevent="submitForm" class="form-example">
    <div class="form-group">
      <label>Username</label>
      <OAutoComplete
        v-model="formData.username"
        :items="usernames"
        placeholder="Search for a username..."
      />
      <span v-if="formErrors.username" class="error">{{
        formErrors.username
      }}</span>
    </div>

    <div class="form-group">
      <label>Skills</label>
      <OAutoComplete
        v-model="formData.skills"
        :items="skills"
        :multiple="true"
        placeholder="Select your skills..."
      />
      <span v-if="formErrors.skills" class="error">{{
        formErrors.skills
      }}</span>
    </div>

    <div class="form-group">
      <label>Country</label>
      <OAutoComplete
        v-model="formData.country"
        :items="countries"
        :clearable="true"
        placeholder="Search for your country..."
      />
      <span v-if="formErrors.country" class="error">{{
        formErrors.country
      }}</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: [],
  country: null,
});

const formErrors = reactive({
  username: "",
  skills: "",
  country: "",
});

const usernames = ref([
  { text: "john_doe", value: "john" },
  { text: "jane_smith", value: "jane" },
  { text: "bob_wilson", value: "bob" },
  { text: "alice_wonder", value: "alice" },
]);

const skills = ref([
  { text: "JavaScript", value: "js" },
  { text: "TypeScript", value: "ts" },
  { text: "Vue.js", value: "vue" },
  { text: "React", value: "react" },
  { text: "Node.js", value: "node" },
  { text: "Python", value: "python" },
  { text: "Docker", value: "docker" },
  { text: "Kubernetes", value: "k8s" },
]);

const countries = ref([
  { text: "United States", value: "us" },
  { text: "United Kingdom", value: "uk" },
  { text: "Canada", value: "ca" },
  { text: "Australia", value: "au" },
  { text: "Germany", value: "de" },
  { text: "France", value: "fr" },
  { text: "Japan", value: "jp" },
  { text: "India", value: "in" },
]);

const validateForm = () => {
  formErrors.username = !formData.username ? "Username is required" : "";
  formErrors.skills =
    formData.skills.length === 0 ? "At least one skill is required" : "";
  formErrors.country = !formData.country ? "Country is required" : "";
};

const submitForm = () => {
  validateForm();
  if (!formErrors.username && !formErrors.skills && !formErrors.country) {
    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>

Demo