Autocomplete

Extended input that provide suggestions while the user types. Use with Field to access all functionalities

<template>
    <section>
        <p class="content"><b>Selected:</b> {{ selected }}</p>
        <b-field label="Find a JS framework">
            <b-autocomplete
                rounded
                v-model="name"
                :data="filteredDataArray"
                placeholder="e.g. jQuery"
                icon="magnify"
                clearable
                @select="option => selected = option">
                <template #empty>No results found</template>
            </b-autocomplete>
        </b-field>
    </section>
</template>

<script>
export default {
    data() {
        return {
            data: [
                'Angular',
                'Angular 2',
                'Aurelia',
                'Backbone',
                'Ember',
                'jQuery',
                'Meteor',
                'Node.js',
                'Polymer',
                'React',
                'RxJS',
                'Vue.js'
            ],
            name: '',
            selected: null
        }
    },
    computed: {
        filteredDataArray() {
            return this.data.filter((option) => {
                return option
                    .toString()
                    .toLowerCase()
                    .indexOf(this.name.toLowerCase()) >= 0
            })
        }
    }
}
</script>

# Object array

<template>
    <section>
        <b-field grouped group-multiline>
            <div class="control">
                <b-switch v-model="openOnFocus">
                    Open dropdown on focus
                </b-switch>
            </div>
            <div class="control">
                <b-switch v-model="keepFirst">
                    Keep-first
                    <small>(will always have first option pre-selected)</small>
                </b-switch>
            </div>
            <div class="control">
                <b-switch v-model="clearable">
                    Clearable
                </b-switch>
            </div>
        </b-field>
        <p class="content"><b>Selected:</b> {{ selected }}</p>
        <b-field label="Find a name">
            <b-autocomplete
                v-model="name"
                placeholder="e.g. Anne"
                :keep-first="keepFirst"
                :open-on-focus="openOnFocus"
                :data="filteredDataObj"
                field="user.first_name"
                @select="option => (selected = option)"
                :clearable="clearable"
            />
        </b-field>
    </section>
</template>

<script>
const data = require('@/data/sample.json')

export default {
    data() {
        return {
            data,
            keepFirst: false,
            openOnFocus: false,
            name: '',
            selected: null,
            clearable: false
        }
    },
    computed: {
        filteredDataObj() {
            return this.data.filter((option) => {
                return (
                    option.user.first_name
                        .toString()
                        .toLowerCase()
                        .indexOf(this.name.toLowerCase()) >= 0
                )
            })
        }
    }
}
</script>

You can add your custom header to the autocomplete.

Selected:

<template>
    <section>
        <b-field grouped group-multiline>
            <div class="control">
                <b-switch v-model="openOnFocus">
                    Open dropdown on focus
                </b-switch>
            </div>
            <div class="control">
                <b-switch v-model="keepFirst">
                    Keep-first
                    <small>(will always have first option pre-selected)</small>
                </b-switch>
            </div>
            <div class="control">
                <b-switch v-model="selectable">
                    Selectable
                </b-switch>
            </div>
        </b-field>
        <p class="content"><b>Selected:</b> {{ selected }}</p>
        <b-field label="Find or add a Fruit">
            <b-autocomplete
                v-model="name"
                ref="autocomplete"
                :data="filteredDataArray"
                :keep-first="keepFirst"
                :open-on-focus="openOnFocus"
                placeholder="e.g. Orange"
                @select="option => selected = option"
                @select-header="showAddFruit"
                :selectable-header="selectable">
                <template #header>
                    <a><span> Add new... </span></a>
                </template>
                <template #empty>No results for {{ name }}</template>
            </b-autocomplete>
        </b-field>
    </section>
</template>

<script>
export default {
    data() {
        return {
            data: [
                'Orange',
                'Apple',
                'Banana',
                'Pear',
                'Lemon',
                'Strawberry',
                'Kiwi'
            ],
            name: '',
            selected: null,
            keepFirst: false,
            openOnFocus: false,
            selectable: false
        }
    },
    computed: {
        filteredDataArray() {
            return this.data.filter((option) => {
                return option
                    .toString()
                    .toLowerCase()
                    .indexOf(this.name.toLowerCase()) >= 0
            })
        }
    },
    methods: {
        showAddFruit() {
            this.$buefy.dialog.prompt({
                message: `Fruit`,
                inputAttrs: {
                    placeholder: 'e.g. Watermelon',
                    maxlength: 20,
                    value: this.name
                },
                confirmText: 'Add',
                onConfirm: (value) => {
                    this.data.push(value)
                    this.$refs.autocomplete.setSelected(value)
                }
            })
        }
    }
}
</script>

Since0.7.6

You can add your custom footer to the autocomplete.

<template>
    <section>
        <b-field grouped group-multiline>
            <div class="control">
                <b-switch v-model="selectable">
                    Selectable
                </b-switch>
            </div>
        </b-field>
        <p class="content"><b>Selected:</b> {{ selected }}</p>
        <b-field label="Find or add a Fruit">
            <b-autocomplete
                v-model="name"
                ref="autocomplete"
                :data="filteredDataArray"
                placeholder="e.g. Orange"
                @select="option => selected = option"
                @select-footer="showAddFruit"
                :selectable-footer="selectable">
                <template #footer>
                    <a><span> Add new... </span></a>
                </template>
                <template #empty>No results for {{ name }}</template>
            </b-autocomplete>
        </b-field>
    </section>
</template>

<script>
export default {
    data() {
        return {
            data: [
                'Orange',
                'Apple',
                'Banana',
                'Pear',
                'Lemon',
                'Strawberry',
                'Kiwi'
            ],
            name: '',
            selected: null,
            selectable: false
        }
    },
    computed: {
        filteredDataArray() {
            return this.data.filter((option) => {
                return option
                    .toString()
                    .toLowerCase()
                    .indexOf(this.name.toLowerCase()) >= 0
            })
        }
    },
    methods: {
        showAddFruit() {
            this.$buefy.dialog.prompt({
                message: `Fruit`,
                inputAttrs: {
                    placeholder: 'e.g. Watermelon',
                    maxlength: 20,
                    value: this.name
                },
                confirmText: 'Add',
                onConfirm: (value) => {
                    this.data.push(value)
                    this.$refs.autocomplete.setSelected(value)
                }
            })
        }
    }
}
</script>

# Groups

Since0.9.2

You can show options by groups

<template>
    <section>
        <p class="content"><b>Selected:</b> {{ selected }}</p>
        <b-field label="Find a food">
            <b-autocomplete
                v-model="name"
                group-field="type"
                group-options="items"
                open-on-focus
                :data="filteredDataObj"
                @select="option => (selected = option)"
            />
        </b-field>
    </section>
</template>

<script>

export default {
    data() {
        return {
            data: [
                {
                    type: 'Fruit',
                    items: ['Apple', 'Banana', 'Watermelon']
                },
                {
                    type: 'Vegetables',
                    items: ['Carrot', 'Broccoli', 'Cucumber', 'Onion']
                }
            ],
            name: '',
            selected: null
        }
    },
    computed: {
        filteredDataObj() {
            const newData = []
            this.data.forEach((element) => {
                const items = element.items.filter((item) =>
                    item.toLowerCase().indexOf(this.name.toLowerCase()) >= 0)
                if (items.length) {
                    newData.push({ type: element.type, items })
                }
            })
            return newData
        }
    }
}
</script>

# Keep First

Since0.9.9

You can select the first option when pressing enter or tab with keep-first.

Additionally, use select-on-click-outside to automatically select the first element when clicking outside of the input element.

Selected:

<template>
    <section>
        <b-field grouped group-multiline>
            <div class="control">
                <b-switch v-model="selectOutside">
                    Select On Clicking Outside
                </b-switch>
            </div>
        </b-field>
        <p class="content"><b>Selected:</b> {{ selected }}</p>
        <b-field label="Find a fruit and press Enter or Tab to select">
            <b-autocomplete
                v-model="name"
                ref="autocomplete"
                :data="filteredDataArray"
                :select-on-click-outside="selectOutside"
                placeholder="e.g. Orange"
                keep-first
                @select="option => selected = option">
                <template #empty>No results for {{ name }}</template>
            </b-autocomplete>
        </b-field>
    </section>
</template>

<script>
export default {
    data() {
        return {
            data: [
                'Orange',
                'Apple',
                'Banana',
                'Pear',
                'Lemon',
                'Strawberry',
                'Kiwi'
            ],
            name: '',
            selected: null,
            selectOutside: false
        }
    },
    computed: {
        filteredDataArray() {
            return this.data.filter((option) => {
                return option
                    .toString()
                    .toLowerCase()
                    .indexOf(this.name.toLowerCase()) >= 0
            })
        }
    }
}
</script>

# Async with custom template

You can have a custom template by adding a scoped slot to it.

API from TMDb.

Selected:

<template>
    <section>
        <p class="content"><b>Selected:</b> {{ selected }}</p>
        <b-field label="Find a movie">
            <b-autocomplete
                :data="data"
                placeholder="e.g. Fight Club"
                field="title"
                :loading="isFetching"
                @typing="getAsyncData"
                @select="option => selected = option">

                <template slot-scope="props">
                    <div class="media">
                        <div class="media-left">
                            <img width="32" :src="`https://image.tmdb.org/t/p/w500/${props.option.poster_path}`">
                        </div>
                        <div class="media-content">
                            {{ props.option.title }}
                            <br>
                            <small>
                                Released at {{ props.option.release_date }},
                                rated <b>{{ props.option.vote_average }}</b>
                            </small>
                        </div>
                    </div>
                </template>
            </b-autocomplete>
        </b-field>
    </section>
</template>

<script>
import debounce from 'lodash/debounce'

export default {
    data() {
        return {
            data: [],
            selected: null,
            isFetching: false
        }
    },
    methods: {
        // You have to install and import debounce to use it,
        // it's not mandatory though.
        getAsyncData: debounce(function (name) {
            if (!name.length) {
                this.data = []
                return
            }
            this.isFetching = true
            this.$http.get(`https://api.themoviedb.org/3/search/movie?api_key=bb6f51bef07465653c3e553d6ab161a8&query=${name}`)
                .then(({ data }) => {
                    this.data = []
                    data.results.forEach((item) => this.data.push(item))
                })
                .catch((error) => {
                    this.data = []
                    throw error
                })
                .finally(() => {
                    this.isFetching = false
                })
        }, 500)
    }
}
</script>

# Async with infinite scroll

With check-infinite-scroll and infinite-scroll event you can listen to the end of the scroll list to implement an infinite scroll strategy.

API from TMDb.

Selected:

<template>
    <section>
        <p class="content"><b>Selected:</b> {{ selected }}</p>
        <b-field label="Find a movie">
            <b-autocomplete
                :data="data"
                placeholder="e.g. Fight Club"
                field="title"
                :loading="isFetching"
                :check-infinite-scroll="true"
                @typing="getAsyncData"
                @select="option => selected = option"
                @infinite-scroll="getMoreAsyncData">

                <template slot-scope="props">
                    <div class="media">
                        <div class="media-left">
                            <img width="32" :src="`https://image.tmdb.org/t/p/w500/${props.option.poster_path}`">
                        </div>
                        <div class="media-content">
                            {{ props.option.title }}
                            <br>
                            <small>
                                Released at {{ props.option.release_date }},
                                rated <b>{{ props.option.vote_average }}</b>
                            </small>
                        </div>
                    </div>
                </template>
                <template #footer>
                    <span v-show="page > totalPages" class="has-text-grey">
                        Thats it! No more movies found.
                    </span>
                </template>
            </b-autocomplete>
        </b-field>
    </section>
</template>

<script>
import debounce from 'lodash/debounce'

export default {
    data() {
        return {
            data: [],
            selected: null,
            isFetching: false,
            name: '',
            page: 1,
            totalPages: 1
        }
    },
    methods: {
        // You have to install and import debounce to use it,
        // it's not mandatory though.
        getAsyncData: debounce(function (name) {
            // String update
            if (this.name !== name) {
                this.name = name
                this.data = []
                this.page = 1
                this.totalPages = 1
            }
            // String cleared
            if (!name.length) {
                this.data = []
                this.page = 1
                this.totalPages = 1
                return
            }
            // Reached last page
            if (this.page > this.totalPages) {
                return
            }
            this.isFetching = true
            this.$http.get(`https://api.themoviedb.org/3/search/movie?api_key=bb6f51bef07465653c3e553d6ab161a8&query=${name}&page=${this.page}`)
                .then(({ data }) => {
                    data.results.forEach((item) => this.data.push(item))

                    this.page++
                    this.totalPages = data.total_pages
                })
                .catch((error) => {
                    throw error
                })
                .finally(() => {
                    this.isFetching = false
                })
        }, 500),
        getMoreAsyncData: debounce(function () {
            this.getAsyncData(this.name)
        }, 250)
    }
}
</script>

# API

Name
Description
Type
Values
Default
v-modelBinding valueString, Number
dataOptions / suggestionsArray, Array, Array
fieldProperty of the object (if data is array of objects) to use as display text, and to keep track of selected optionStringvalue
custom-formatterFunction to format an option to a string for display in the input as alternative to field prop)Function
group-fieldProperty of the object (if data is array of objects) to use as display text of groupString
group-optionsProperty of the object (if data is array of objects) to use as key to get items array of each group, optionalString
clear-on-selectClear input text on selectBooleanfalse
open-on-focusOpen dropdown list on focusBooleanfalse
keep-firstThe first option will always be pre-selected (easier to just hit enter or tab)Booleanfalse
sizeVertical size of input, optionalStringis-small, is-medium, is-large
expandedMakes input full width when inside a grouped or addon fieldBooleanfalse
loadingAdd the loading state to the inputBooleanfalse
iconIcon name to be addedString
icon-packIcon pack to useStringmdi, fa, fas, far, fad, falmdi
confirm-keysArray of keys (https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values) which will select an option when typing (default tab and enter)Array["Tab", "Enter"]
clearableAdd a button to clear the inputed textBooleanfalse
icon-rightIcon name to be added on the right sideString
maxlengthSame as native maxlength, plus character counterString, Number
check-infinite-scrollMakes the component check if list reached scroll end and emit infinite-scroll event.Booleanfalse
max-heightMax height of dropdown contentString, Number200px
dropdown-positionPosition of dropdownStringtop, bottom, autoauto
append-to-bodyAppend autocomplete content to body (prevents event bubbling)Booleanfalse
select-on-click-outsideTrigger the @select event for the first pre-selected option when clicking outside and keep-first is enabledBooleanfalse
selectable-headerAllows the header in the autocomplete to be selectableBooleanfalse
selectable-footerAllows the footer in the autocomplete to be selectableBooleanfalse
Any native attribute

# Variables

You can use these variables to customize this component.

Name
Default
$dropdown-content-max-height200px

This page is open source. Noticed a typo or something's unclear?

Improve this page on GitHub