-
Storybook Helpful to see all variations of component's props.
-
JSFiddle Helpful for playing around and sharing.
-
Codesandbox Demos:
- WAI-ARIA complete autosuggest component built with the power of Vue.
- Full control over rendering with built in defaults or custom components for rendering.
- Easily integrate AJAX data fetching for list presentation.
- Supports multiple sections.
- No opinions on CSS, full control over styling.
- Rigorously tested.
This module is distributed via npm which is bundled with node and
should be installed as one of your project's dependencies
:
npm install --save vue-autosuggest
or
yarn add vue-autosuggest
Load VueAutosuggest into your vue app globally.
import VueAutosuggest from "vue-autosuggest";
Vue.use(VueAutosuggest);
or locally inside a component:
import { VueAutosuggest } from 'vue-autosuggest';
export default {
...
components: {
VueAutosuggest
}
...
};
Place the component into your app!
<vue-autosuggest
:suggestions="[{data:['Frodo', 'Samwise', 'Gandalf', 'Galadriel', 'Faramir', 'Éowyn']}]"
:input-props="{id:'autosuggest__input', onInputChange: onInputChange, placeholder:'Do you feel lucky, punk?'}"
@selected="selectHandler"
@click="clickHandler"
>
<template slot-scope="{suggestion}">
<span class="my-suggestion-item">{{suggestion.item}}</span>
</template>
</vue-autosuggest>
Advanced usage:
Click to expand
<template>
<div>
<h1>Vue-autosuggest 🔮</h1>
<div style="padding-top:10px; margin-bottom: 10px;"><span v-if="selected">You have selected '{{JSON.stringify(selected,null,2)}}'</span></div>
<vue-autosuggest
:suggestions="filteredOptions"
@focus="focusMe"
@click="clickHandler"
@selected="onSelected"
:render-suggestion="renderSuggestion"
:get-suggestion-value="getSuggestionValue"
:input-props="{id:'autosuggest__input', onInputChange: this.onInputChange, placeholder:'Do you feel lucky, punk?'}"/>
</div>
</template>
<script>
import { VueAutosuggest } from "vue-autosuggest";
export default {
components: {
VueAutosuggest
},
data() {
return {
selected: "",
filteredOptions: [],
suggestions: [
{
data: [
{ id: 1, name: "Frodo", avatar: "./frodo.jpg" },
{ id: 2, name: "Samwise", avatar: "./samwise.jpg" },
{ id: 3, name: "Gandalf", avatar: "./gandalf.png" },
{ id: 4, name: "Aragorn", avatar: "./aragorn.jpg" }
]
}
]
};
},
methods: {
onInputChange(text, oldText) {
if (text === null) {
/* Maybe the text is null but you wanna do
* something else, but don't filter by null.
*/
return;
}
// Full customizability over filtering
const filteredData = this.suggestions[0].data.filter(option => {
return option.name.toLowerCase().indexOf(text.toLowerCase()) > -1;
});
// Store data in one property, and filtered in another
this.filteredOptions = [{ data: filteredData }];
},
clickHandler(item) {
// items are selected by default on click, but you can add some more behavior here!
},
onSelected(item) {
this.selected = item;
},
/**
* renderSuggestion will override the default suggestion template slot.
*/
renderSuggestion(suggestion) {
/* You will need babel-plugin-transform-vue-jsx for this kind of syntax for
* rendering. If you don't use babel or the jsx transform, then you can create
* the you can create the virtual node yourself using this.$createElement.
*/
const character = suggestion.item;
return (
<div
style={{
display: "flex",
alignItems: "center"
}}
>
<img
style={{
width: "25px",
height: "25px",
borderRadius: "15px",
marginRight: "10px"
}}
src={character.avatar}
/>{" "}
<span style={{ color: "navyblue" }}>{character.name}</span>
</div>
);
},
/**
* This is what the <input/> value is set to when you are selecting a suggestion.
*/
getSuggestionValue(suggestion) {
return suggestion.item.name;
},
focusMe(e) {
console.log(e)
}
}
};
</script>
For more advanced usage, check out the examples below, and explore the properties you can use.
Slots for injecting content above all the results inside the results container.
<vue-autosuggest ...>
<template slot="header">
<h1>header content goes here</h1>
</template>
<template slot="footer">
<h1>footer content goes here</h1>
</template>
</vue-autosuggest>
Used to style each suggestion inside the <li>
tag. Using scoped slots
you have access to the suggestion
item inside the v-for
suggestions loop. This gives you the power of Vue templating, since
vue-autosuggest does not have an opinion about how you render the items in your list.
<vue-autosuggest>
<template slot-scope="{suggestion}">
<!-- suggestion.name corresponds to which section the item is in -->
<div v-if="suggestion.name === 'blog'">
<!-- suggestion.item corresponds to the suggestion object -->
<a target="_blank" :href="suggestion.item.url">{{suggestion.item.value}}</a>
</div>
<div v-else>{{suggestion.item}}</div>
</template>
</vue-autosuggest>
This slot will be overridden when the
render-suggestion
prop is used.
Prop | Type | Required | Description |
---|---|---|---|
suggestions |
Array | ✓ | Suggestions to be rendered. e.g.suggestions: [{data: ['harry','ron','hermione']}] |
input-props |
Object | ✓ | Add props to the <input> . |
section-configs |
Object | Define multiple sections <input> . |
|
render-suggestion |
Function | Tell vue-autosuggest how to render inside the <li> tag. Overrides what is inside the default suggestion template slot. |
|
get-suggestion-value |
Function | Tells vue-autosuggest what to put in the <input/> value |
|
@selected |
Function | ✓ | suggestion select handler. equivalent to sectionConfigs on-selected but for all items |
component-attr-id-autosuggest |
String | id of entire component |
|
component-attr-class-autosuggest-results-container |
String | class of container of results container |
|
component-attr-class-autosuggest-results |
String | class of results container |
Prop | Type | Required | Description |
---|---|---|---|
id |
String | ✓ | id attribute on <input> . |
on-input-change |
Function | ✓ | Triggers everytime the <input> changes. This is triggered via a Vue watcher, so you have both current value, and previous value access e.g. onInputChange(text, oldText) |
Deprecated | @click which will map to the underlying <input /> |
||
Deprecated | @blur which will map to the underlying <input /> |
||
Deprecated | @focus which will map to the underlying <input /> |
||
initial-value |
String | Set some initial value for the <input> . |
|
Any DOM Props | * | You can add any props to <input> as the component will v-bind inputProps. Similar to rest spread in JSX. See more details here: https://vuejs.org/v2/api/#v-bind. The name attribute is set to "q " by default. |
Multiple sections can be defined in the sectionConfigs
prop which defines the control behavior for
each section.
Prop | Type | Required | Description |
---|---|---|---|
on-selected |
Function | ✓ | Determine behavior for what should happen when a suggestion is selected. e.g. Submit a form, open a link, update a vue model, tweet at Ken Wheeler etc. |
type |
String | Vue component name for specifying which type to implement using Vue's <component :is="componentName"></component> functionality. See DefaultSection.vue for scaffolding a new type. You must declare your component in the scope of the app using Vue.component() . You can extend DefaultSection using extends . See UrlSection for an example. |
|
limit |
Number | Limit each section by some value. Default: Infinity |
Below we have defined a default
section and a blog
section. The blog
section has a component
type
of url-section
which corresponds to which component the Autosuggest loads. When type is not
defined, Vue-autosuggest will use a built in DefaultSection.vue
component.
sectionConfigs: {
'default': {
limit: 6,
onSelected: function(item, originalInput) {
console.log(item, originalInput, `Selected "${item.item}"`);
}
},
'blog': {
limit: 3,
type: "url-section",
onSelected: function() {
console.log("url: " + item.item.url);
}
}
}
This function can be used to tell vue-autosuggest how to render the html inside the <li>
tag when you do not want to use the
default template slot for suggestions but would rather have the power of javascript / jsx.
In its most basic form it just returns an object property:
renderSuggestion(suggestion) {
return suggestion.name;
},
But usually it returns a JSX fragment, which is transformed into a virtual node description with babel-plugin-transform-vue-jsx:
renderSuggestion(suggestion) {
return <div style={{ color: "red" }}>{suggestion.name}</div>;
},
If you're not using babel-plugin-transform-vue-jsx, you can create the virtual node description yourself:
renderSuggestion(suggestion) {
return this.$createElement('div', { 'style': { color: 'red'} }, suggestion.name);
},
This function will tell vue-autosuggest what to put in the <input/>
as the value.
getSuggestionValue(suggestion) {
return suggestion.name;
},
How do I update the input programatically?
- You can assign a ref to the component
<vue-autosuggest ref="myRefName" ... />
and then access the input value throughthis.$refs.myRefName.searchInput
. This is useful mainly for clearing the input.⚠️ Note, refs are more of an "escape hatch" as they call it, so it won't trigger theonInputChange
method.
- Misha Moroshko's react-autosuggest component inspired the api + WAI-ARIA completeness https://github.com/moroshko/react-autosuggest
- Spatie inspired the vue component setup + docs https://github.com/spatie/vue-table-component
Thanks goes to these people (emoji key):
Darren Jennings 💻 📖 🚇 |
Evgeniy Kulish 💻 🎨 💡 |
---|
This project follows the all-contributors specification. Contributions of any kind welcome!
MIT