vue-autosuggest

Vue autosuggest component.

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
vue-autosuggest
2.2.04 years ago7 years agoMinified + gzip package size for vue-autosuggest in KB

Readme

ο»Ώ

Vue logo


vue-autosuggest

πŸ” Autosuggest component built for Vue.




!Build Statusbuild-badgebuild !Code Coveragecoverage-badgecoverage !versionversion-badgepackage !downloadsdownloads-badgenpmtrends !MIT Licenselicense-badgeLICENSE !gzip sizesize-badge
All Contributors !PRs Welcomeprs-badgeprs !Code of Conductcoc-badgecoc
!Watch on GitHubgithub-watch-badgegithub-watch !Star on GitHubgithub-star-badgegithub-star !Tweettwitter-badgetwitter

Table of Contents

Examples

variations of component's props.
and sharing.
  • Codesandbox Demos:

Deeply nested data objects as suggestions Api Fetching suggestions with Multiple sections Form Validation with VeeValidate Multiple VueAutosuggest instances on same page

Features

  • 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.

Installation

This module is distributed via npmnpm which is bundled with nodenode and should be installed as one of your project's dependencies:
npm install vue-autosuggest

or
yarn add vue-autosuggest

Usage

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', placeholder:'Do you feel lucky, punk?'}"
    @input="onInputChange"
    @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 class="demo">
    <div v-if="selected" style="padding-top:10px; width: 100%;">
      You have selected <code>{{selected.name}}, the {{selected.race}}</code>
    </div>
    <div class="autosuggest-container">
      <vue-autosuggest
        v-model="query"
        :suggestions="filteredOptions"
        @focus="focusMe"
        @click="clickHandler"
        @input="onInputChange"
        @selected="onSelected"
        :get-suggestion-value="getSuggestionValue"
        :input-props="{id:'autosuggest__input', placeholder:'Do you feel lucky, punk?'}">
        <div slot-scope="{suggestion}" style="display: flex; align-items: center;">
          <img :style="{ display: 'flex', width: '25px', height: '25px', borderRadius: '15px', marginRight: '10px'}" :src="suggestion.item.avatar" />
          <div style="{ display: 'flex', color: 'navyblue'}">{{suggestion.item.name}}</div>
        </div>
      </vue-autosuggest>
    </div>
  </div>
</template>

<script>
import { VueAutosuggest } from "vue-autosuggest";

export default {
  components: {
    VueAutosuggest
  },
  data() {
    return {
      query: "",
      selected: "",
      suggestions: [
        {
          data: [
            { id: 1, name: "Frodo", race: "Hobbit", avatar: "https://upload.wikimedia.org/wikipedia/en/thumb/4/4e/Elijah_Wood_as_Frodo_Baggins.png/220px-Elijah_Wood_as_Frodo_Baggins.png" },
            { id: 2, name: "Samwise", race: "Hobbit", avatar: "https://upload.wikimedia.org/wikipedia/en/thumb/7/7b/Sean_Astin_as_Samwise_Gamgee.png/200px-Sean_Astin_as_Samwise_Gamgee.png" },
            { id: 3, name: "Gandalf", race: "Maia", avatar: "https://upload.wikimedia.org/wikipedia/en/thumb/e/e9/Gandalf600ppx.jpg/220px-Gandalf600ppx.jpg" },
            { id: 4, name: "Aragorn", race: "Human", avatar: "https://upload.wikimedia.org/wikipedia/en/thumb/3/35/Aragorn300ppx.png/150px-Aragorn300ppx.png" }
          ]
        }
      ]
    };
  },
  computed: {
    filteredOptions() {
      return [
        { 
          data: this.suggestions[0].data.filter(option => {
            return option.name.toLowerCase().indexOf(this.query.toLowerCase()) > -1;
          })
        }
      ];
    }
  },
  methods: {
    clickHandler(item) {
      // event fired when clicking on the input
    },
    onSelected(item) {
      this.selected = item.item;
    },
    onInputChange(text) {
      // event fired when the input changes
      console.log(text)
    },
    /**
     * 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) // FocusEvent
    }
  }
}
</script>

<style>
.demo { 
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}

input {
  width: 260px;
  padding: 0.5rem;
}

ul {
  width: 100%;
  color: rgba(30, 39, 46,1.0);
  list-style: none;
  margin: 0;
  padding: 0.5rem 0 .5rem 0;
}
li {
  margin: 0 0 0 0;
  border-radius: 5px;
  padding: 0.75rem 0 0.75rem 0.75rem;
  display: flex;
  align-items: center;
}
li:hover {
  cursor: pointer;
}

.autosuggest-container {
  display: flex;
  justify-content: center;
  width: 280px;
}

#autosuggest { width: 100%; display: block;}
.autosuggest__results-item--highlighted {
  background-color: rgba(51, 217, 178,0.2);
}
</style>


For more advanced usage, check out the examples below, and explore the properties you can use.

Slots

header/footer

Slots for injecting content around the results/input. Useful for header/footer like slots or empty state.
<vue-autosuggest ...>
  <template slot="before-input"> content before the <input /> goes here </template>
  <template slot="after-input"> content after the <input /> goes here </template>
  <template slot="before-suggestions"> content before the <ul> goes here </template>
  <template slot="before-section-<section.name e.g. 'default'>"> section header content for specific section goes here </template>
  <template slot="after-section-<section.name e.g. 'default'>"> footer content goes here for specific section. </template>
  <template slot="after-section"> Default footer content for all sections </template>
  <template slot="after-suggestions"> content after the <ul> goes here </template>
</vue-autosuggest>

Adding labels

It is common in forms to add a label next to the <input /> tag for semantic html / accessibility. You can use the before-input slot to accomplish this in conjunction with the inputProps.id:
<vue-autosuggest ...>
  <template slot="before-input">
    <label :for="inputProps.id">Search here:</label>
  </template>
  ...
</vue-autosuggest>

suggestion item (i.e. default slot)

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.

Props

| 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 | | should-render-suggestions | Function | | Tell vue-autosuggest if it should render the suggestions results popover | | 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 | | component-attr-prefix | String | | prefix to be used for results item classes/ids. default: autosuggest |

inputProps

| Prop | Type | Required | Description | | :----------------------- | :------------------ | :--------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | id | String | βœ“ | id attribute on <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. |

sectionConfigs

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. | | 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);
        }
    }
}

renderSuggestion

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);
},

getSuggestionValue

This function will tell vue-autosuggest what to put in the <input/> as the value.
getSuggestionValue(suggestion) {
    return suggestion.item.name;
},

shouldRenderSuggestions

This function will tell vue-autosuggest if it should display the suggestions popover
/**
 * @param {Array} size - total results displayed
 * @param {Boolean} loading - value that indicates if vue-autosuggest _thinks_ that the 
 *                            the popover should be open (e.g. if user hit escape, or
 *                            user clicked away)
 * @returns {Boolean}
 */
shouldRenderSuggestions (size, loading) {
  // This is the default behavior
  return size >= 0 && !loading
}

Events

Below are the list of supported events. @ is short-hand for v-on.
| Prop | Returns | Description | | :-------------------------------- | :-------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | @selected | suggestionItem, index | suggestion select handler. equivalent to sectionConfigs on-selected but for all items | | @input, @focus, @blur, etc. | \* | there is a transparent wrapper on the underlying <input /> so vue-autosuggest will use any DOM event you pass it for listening. This is implemented using v-on:<event>. | | @opened, @closed | \* | suggestions visibility handler, indicates when the suggestions are opened and closed. This is called alongside shouldRenderSuggestions. | | @item-changed | suggestionItem, index | when keying through the results, this event signals which item is highlighted before being selected. |

Browser support

For IE11 and below, some functionality may not work. For example, you will have to manually polyfill Node.prototype.contains

Inspiration

  • Misha Moroshko's react-autosuggest component inspired the api + WAI-ARIA completeness
https://github.com/moroshko/react-autosuggest

Contributors

Thanks goes to these people (emoji keyemojis):
|
Darren Jennings

πŸ’» πŸ“– πŸš‡") ⚠️ 🎨 πŸ’‘ |
Evgeniy Kulish

πŸ’» 🎨 πŸ’‘ ⚠️ |
Scott Smith

πŸ› πŸ’» ⚠️ |
Fernando Machuca

🎨 |
BerniML

πŸ’» ⚠️ |
Kristoffer NordstrΓΆm

πŸ’» ⚠️ | | :---: | :---: | :---: | :---: | :---: | :---: |
Thanks to @chuca for the logo design.
This project follows the all-contributorsall-contributors specification. Contributions of any kind welcome!

LICENSE

MIT