# Autocomplete
The mx-autocomplete
component wraps both a text input and a menu to provide autocomplete / typeahead functionality.
# Component-provided filtering
# Basic string filtering
The autocomplete component can perform basic filtering/searching of options
if the filterOptions
prop is true.
<mx-autocomplete
label="Search"
placeholder="Apple, banana..."
:options.prop="['apple', 'banana', 'pineapple', 'grape']"
filter-options
@mxSelect="onSelect"
/>
2
3
4
5
6
# Filtering objects by property
It can also render and filter objects. If set to a string, the optionLabel
prop specifies which property of the option object should be displayed and used for filtering.
The example below also demonstrates setting the optionIcon
prop to an icon class name. See also Setting the label and icon using functions.
<mx-autocomplete
label="Search"
placeholder="Apple, banana..."
:options.prop="[
{ name: 'apple' },
{ name: 'banana' },
{ name: 'pineapple' },
{ name: 'grape' },
]"
filter-options
option-label="name"
option-icon="mds-cross"
@mxSelect="onSelect"
/>
2
3
4
5
6
7
8
9
10
11
12
13
# Custom filtering function
More complex filtering can be performed by passing a function for the filterOptions
prop. This function should accept the current input value as the first parameter, and an options
member as the second.
In the example below, the user can search for "california"
or "florida"
in addition to "hollywood"
, "seattle"
, etc.
I'm also demonstrating how to set the filterOptions
property in a separate script (rather than using Vue's .prop
modifier), which may be necessary if your host application is using vanillla JavaScript or cannot pass a function to an element from a framework template.
<mx-autocomplete
class="city-state-autocomplete"
label="Search"
placeholder="Hollywood, Miami, Alaska..."
option-label="city"
:options.prop="[
{ city: 'Anchorage', state: 'Alaska' },
{ city: 'Austin', state: 'Texas' },
{ city: 'Hollywood', state: 'California' },
{ city: 'Miami', state: 'Florida' },
{ city: 'Orlando', state: 'Florida' },
{ city: 'Sacramento', state: 'California' },
{ city: 'Seattle', state: 'Washington' }
]"
@mxSelect="onSelect"
/>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Get a reference to the element, and then set the `filterOptions` property.
const autocomplete = document.querySelector('.city-state-autocomplete');
autocomplete.filterOptions = (inputValue, option) => {
// Search both the city and state for the input value
inputValue = inputValue.toLowerCase();
if (option.city.toLowerCase().includes(inputValue)) return true;
if (option.state.toLowerCase().includes(inputValue)) return true;
return false;
};
2
3
4
5
6
7
8
9
10
# External filtering
If the matching options
need to be fetched from an API call or filtered in the host application, then do not set filterOptions
(or set it to false
). Instead, attach an input
event listener to <mx-autocomplete>
, and then update the options
prop as needed.
<mx-autocomplete
label="Search"
placeholder="Apple, banana..."
:options.prop="filteredFruits"
option-label="name"
@input="searchFruits"
@mxSelect="onSelect"
/>
2
3
4
5
6
7
searchFruits(e) {
// Show no options if the input is empty
if (!e.target.value || !e.target.value.trim()) return this.filteredFruits = [];
const query = e.target.value.trim().toLowerCase();
// This could just as easily be an API query
this.filteredFruits = [
{ name: 'apple' },
{ name: 'banana' },
{ name: 'pineapple' },
{ name: 'grape' }
].filter(fruit => fruit.name.includes(query));
}
2
3
4
5
6
7
8
9
10
11
12
# Set input value on select
The setValueOnSelect
prop allows the text input to be automatically set to the selected option's label without having to attach an mxSelect
event listener. This allows the autocomplete field to be easily used as a named input in a form.
<mx-autocomplete
label="Favorite Beatle"
placeholder="John, Paul..."
:options.prop="['John', 'Paul', 'George', 'Ringo']"
filter-options
set-value-on-select
>
<span slot="no-results">No matching Beatles found</span>
</mx-autocomplete>
2
3
4
5
6
7
8
# Option groups
If a member of the options
array is an array itself, it will be rendered as a group. To specify the headings for all groups (prior to filtering), the optionGroups
prop should be provided.
<mx-autocomplete
label="Search"
placeholder="Apple, banana..."
:option-groups.prop="['Fruits', 'Vegetables']"
:options.prop="[
[
{ name: 'apple' },
{ name: 'banana' },
{ name: 'pineapple' },
{ name: 'grape' }
],
[
{ name: 'lettuce' },
{ name: 'turnip' }
]
]"
filter-options
option-label="name"
@mxSelect="onSelect"
/>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Custom option rendering
# Setting the label and icon using functions
For the sake of customization, functions may be passed for both the optionLabel
and optionIcon
props.
An optionLabel
function should accept the option
as a parameter, and it should return a string, which may contain HTML.
An optionIcon
function should also accept the option
, and it should return an icon class name (or multiple classes separated by a space).
As a reminder, the examples below leverage Vue's .prop
modifier for the sake of brevity. For vanilla JS or other frameworks, you may need to set the element's options
, optionLabel
, and optionIcon
properties in your script. See also Custom filtering function.
<mx-autocomplete
class="city-state-autocomplete"
label="City"
placeholder="Hollywood, Miami, Alaska..."
:option-label.prop="getCityStateLabel"
:option-icon.prop="getCityIcon"
:options.prop="[
{ city: 'Anchorage', state: 'Alaska' },
{ city: 'Austin', state: 'Texas' },
{ city: 'Hollywood', state: 'California' },
{ city: 'Miami', state: 'Florida' },
{ city: 'Orlando', state: 'Florida' },
{ city: 'Sacramento', state: 'California' },
{ city: 'Seattle', state: 'Washington' }
]"
@mxSelect="onSelect"
/>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
getCityStateLabel(option) {
const STATE_ABBR = {
Alaska: 'AK',
California: 'CA',
Florida: 'FL',
Texas: 'TX',
Washington: 'WA'
};
return `${option.city}, ${STATE_ABBR[option.state]}`;
},
getCityIcon(option) {
const CAPITALS = ['Austin', 'Sacramento']; // etc.
return CAPITALS.includes(option.city) ? 'mds-badge-star' : 'ph-bold ph-map-pin';
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Using a non-block input
The inputTag
prop may be used to swap out the default mx-block-input
with mx-input
, mx-search
, or another custom element with a similar interface.
<mx-autocomplete
input-tag="mx-search"
placeholder="Search fruits"
:options.prop="['apple', 'banana', 'pineapple', 'grape']"
filter-options
set-value-on-select
@mxSelect="onSelect"
/>
2
3
4
5
6
7
# Advanced example
The following example dynamically changes many of the autocomplete props based on the "Filter by" dropdown.
<mx-block-wrapper columns="3">
<mx-autocomplete
colspan="2"
label="Search"
:placeholder="searchPlaceholder"
:option-groups.prop="searchGroups"
:options.prop="searchResults"
:option-icon="searchOptionIcon"
option-label="name"
@input="search"
:value="searchQuery"
@mxSelect="addSelection"
/>
<mx-block-select label="Filter by" :value="filterBy" @input="setFilterBy">
<mx-menu-item>Company</mx-menu-item>
<mx-menu-item>Organization</mx-menu-item>
<mx-menu-item>Region</mx-menu-item>
<mx-menu-item>Office</mx-menu-item>
</mx-block-select>
</mx-block-wrapper>
<div class="flex flex-wrap gap-4 my-8">
<mx-chip
v-for="selection in selections"
:key="selection.name"
removable
:icon="getSelectionIcon(selection.type)"
@mxRemove="() => removeSelection(selection)"
>
{{selection.name}}
</mx-chip>
</div>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// ...
data() {
return {
searchQuery: '',
searchResults: [],
filterBy: 'Region',
selections: [],
};
},
computed: {
searchPlaceholder() {
return this.filterBy + ' name';
},
searchGroups() {
const plural = this.filterBy === 'company' ? 'companies' : this.filterBy + 's';
return [plural];
},
searchOptionIcon() {
return this.getSelectionIcon(this.filterBy);
},
},
methods: {
getSelectionIcon(type) {
const icons = {
'Company': 'ph-bold ph-globe',
'Organization': 'ph-bold ph-tree-structure',
'Region': 'ph-bold ph-squares-four',
'Office': 'ph-bold ph-buildings',
};
return icons[type];
},
setFilterBy(e) {
this.filterBy = e.target.value;
this.search();
},
search(e) {
if (e) this.searchQuery = e.target.value?.trim();
if (!this.searchQuery) return this.searchResults = [];
// Return fake results (using an array within an array so items are nested under a group heading)
this.searchResults = [[
{ name: `${this.searchQuery.toUpperCase()} ${this.filterBy}`, type: this.filterBy },
{ name: `Another ${this.searchQuery.toUpperCase()} result`, type: this.filterBy },
{ name: `${this.searchQuery.split('').reverse().join('')}${this.searchQuery}`, type: this.filterBy },
]];
},
addSelection(e) {
const selection = e.detail;
const isAlreadySelected = this.selections.some(s => s.name === selection.name && s.type === selection.type);
if (isAlreadySelected) return;
this.selections = [...this.selections, selection];
},
removeSelection(selection) {
this.selections = this.selections.filter(s => s !== selection);
},
},
// ...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# mx-autocomplete
# Properties
Property | Attribute | Description | Type | Default |
---|---|---|---|---|
assistiveText | assistive-text | string | undefined | |
autofocus | autofocus | boolean | false | |
colspan | colspan | Used to define the number of columns to span in the parent wrapper if more than 1 | number | undefined |
disabled | disabled | boolean | false | |
error | error | boolean | false | |
filterOptions | filter-options | If not provided (or false), options will not be filtered by the component. If true, options are filtered using String.prototype.includes() . If options is not an array of strings, optionLabel should also be set. If a function ((inputValue, option) => boolean ) is passed, that function will be used to filter options against the input value. | ((inputValue: string, option: any) => boolean) \| boolean | false |
inputId | input-id | The id attribute for the text input | string | undefined |
inputTag | input-tag | Set to mx-input , etc. to change which element is used as the input. | string | 'mx-block-input' |
label | label | Text for the label element | string | 'Search' |
maxlength | maxlength | number | undefined | |
name | name | The name attribute for the text input | string | undefined |
optionGroups | -- | An array of group headings if the options are grouped (i.e. options is an array of arrays) | string[] | [] |
optionIcon | option-icon | Class name of icon to show on the left side of each option, or a function (option: any) => string that returns the class name. | ((option: any) => string) \| string | undefined |
optionLabel | option-label | If options is an array of objects, this specifies which property should be displayed in the menu item. If filterOptions is true , this property will also be used for filtering. | string | undefined |
options | -- | Array of options, which may be strings or arbitrary objects. | any[] | undefined |
placeholder | placeholder | Placeholder text for the input | string | undefined |
readonly | readonly | boolean | false | |
setValueOnSelect | set-value-on-select | If set to true, the selected label will become the value of the input | boolean | false |
type | type | The type attribute for the text input | string | 'search' |
value | value | The current search input value | string | undefined |
# Events
Event | Description | Type |
---|---|---|
mxClear | Emitted when the clear button is clicked. | CustomEvent<void> |
mxSelect | Emitted when an option is selected. | CustomEvent<any> |
# Dependencies
# Depends on
# Graph
graph TD;
mx-autocomplete --> mx-menu-item
mx-autocomplete --> mx-menu
mx-menu-item --> mx-checkbox
style mx-autocomplete fill:#f9f,stroke:#333,stroke-width:4px
2
3
4
5
If you are having trouble setting a prop or adding an event listener, refer to this page.
Avatars →