Component Code (AutocompleteInput.vue)
<template>
<div class="mb-3">
<label for="autocomplete-input" class="form-label">{{ label }}</label>
<input
id="autocomplete-input"
type="text"
class="form-control"
v-model="inputValue"
@input="onInput"
@focus="showDropdown = true"
@blur="onBlur"
:placeholder="placeholder"
/>
<ul
class="dropdown-menu w-100"
:class="{ show: showDropdown && filteredSuggestions.length }"
>
<li
v-for="(item, index) in filteredSuggestions"
:key="index"
@mousedown.prevent="selectSuggestion(item)"
class="dropdown-item"
>
{{ item }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "AutocompleteInput",
props: {
label: {
type: String,
default: "Autocomplete",
},
suggestions: {
type: Array,
default: () => [],
},
placeholder: {
type: String,
default: "Type to search...",
},
},
data() {
return {
inputValue: "",
showDropdown: false,
};
},
computed: {
filteredSuggestions() {
const input = this.inputValue.toLowerCase();
return this.suggestions.filter((item) =>
item.toLowerCase().includes(input)
);
},
},
methods: {
onInput() {
this.showDropdown = true;
},
onBlur() {
// Delay hiding dropdown to allow click event to register
setTimeout(() => {
this.showDropdown = false;
}, 200);
},
selectSuggestion(item) {
this.inputValue = item;
this.showDropdown = false;
this.$emit("selected", item);
},
},
};
</script>
<style scoped>
/* Optional: Add custom styles if needed */
</style>
Usage Example
<template>
<div class="mb-3 position-relative">
<label for="autocomplete-input" class="form-label">{{ label }}</label>
<input
id="autocomplete-input"
type="text"
class="form-control"
v-model="inputValue"
@input="onInput"
@focus="showDropdown = true"
@blur="onBlur"
:placeholder="placeholder"
ref="input"
/>
<ul
class="dropdown-menu"
:class="{ show: showDropdown && filteredSuggestions.length }"
:style="{ width: dropdownWidth + 'px' }"
>
<li
v-for="(item, index) in filteredSuggestions"
:key="index"
@mousedown.prevent="selectSuggestion(item)"
class="dropdown-item"
>
{{ item }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "AutocompleteInput",
props: {
label: {
type: String,
default: "Autocomplete",
},
suggestions: {
type: Array,
default: () => [],
},
placeholder: {
type: String,
default: "Type to search...",
},
},
data() {
return {
inputValue: "",
showDropdown: false,
dropdownWidth: 0, // To dynamically match the input width
};
},
computed: {
filteredSuggestions() {
const input = this.inputValue.toLowerCase();
return this.suggestions.filter((item) =>
item.toLowerCase().includes(input)
);
},
},
methods: {
onInput() {
this.showDropdown = true;
},
onBlur() {
// Delay hiding dropdown to allow click event to register
setTimeout(() => {
this.showDropdown = false;
}, 200);
},
selectSuggestion(item) {
this.inputValue = item;
this.showDropdown = false;
this.$emit("selected", item);
},
updateDropdownWidth() {
// Set the dropdown width dynamically based on the input element
if (this.$refs.input) {
this.dropdownWidth = this.$refs.input.offsetWidth;
}
},
},
mounted() {
this.updateDropdownWidth();
window.addEventListener("resize", this.updateDropdownWidth); // Update width on window resize
},
beforeUnmount() {
window.removeEventListener("resize", this.updateDropdownWidth);
},
};
</script>
<style scoped>
/* Ensure dropdown appears directly below the input field */
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
z-index: 1000;
}
</style>
Top comments (0)