Angular Autocomplete - Getting Started

Drop-down editors allow users to navigate through a list of items, select one or multiple items, and search through the list. To learn how to choose a DevExtreme drop-down editor and for more details about the component's features, refer to the following article: How to Choose a Drop-Down Editor.

jQuery
NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.
Angular
NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.
Vue
NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.
React
NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.

Autocomplete is a text box that displays suggestions while a user types.

This tutorial shows how to add an Autocomplete component to the page and configure the component's core settings. As a result, you will create the following UI component:

Each section in this tutorial describes a single configuration step. You can also find the full source code in the GitHub repository.

View on GitHub

Create Autocomplete and Bind It to Data

To create an Autocomplete component, declare it in the markup and bind the component to a data source.

Use one of the following properties to supply data to the component:

If the data source contains objects, you should specify the valueExpr property. It accepts the name of the data field that uniquely identifies each data object.

The code example below specifies the dataSource as an array and sets valueExpr to Subject.

jQuery
index.js
index.html
data.js
$(function() {
    $("#autocomplete").dxAutocomplete({
        dataSource: employeesTasks,
        valueExpr: "Subject"
    });
});
<html>
    <head>
        <!-- ... -->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <link rel="stylesheet" href="https://cdn3.devexpress.com/jslib/24.2.3/css/dx.light.css">
        <script type="text/javascript" src="https://cdn3.devexpress.com/jslib/24.2.3/js/dx.all.js"></script>
        <script type="text/javascript" src="index.js"></script>
        <script type="text/javascript" src="data.js"></script>
    </head>
    <body>
        <div id="autocomplete"></div>
    </body>
</html>
const employeesTasks = [
    {
        ID: 1,
        Assignee: "Mr. John Heart",
        Subject: "Choose between PPO and HMO Health Plan",
        disabled: true
    }, {
        ID: 2,
        Assignee: "Mr. John Heart",
        Subject: "Google AdWords Strategy"
    }, {
        ID: 3,
        Assignee: "Mr. John Heart",
        Subject: "New Brochures"
    }, {
        ID: 4,
        Assignee: "Mr. John Heart",
        Subject: "Update NDA Agreement"
    }, {
        ID: 5,
        Assignee: "Mr. John Heart",
        Subject: "Review Product Recall Report by Engineering Team"
    }, {
        ID: 6,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Update Personnel Files"
    }, {
        ID: 7,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Review Health Insurance Options Under the Affordable Care Act"
    }, {
        ID: 8,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Non-Compete Agreements"
    }, {
        ID: 9,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Give Final Approval for Refunds"
    }, {
        ID: 10,
        Assignee: "Mr. Robert Reagan",
        Subject: "Deliver R&D Plans for 2013"
    }, {
        ID: 11,
        Assignee: "Mr. Robert Reagan",
        Subject: "Decide on Mobile Devices to Use in the Field"
    }, {
        ID: 12,
        Assignee: "Mr. Robert Reagan",
        Subject: "Try New Touch-Enabled WinForms Apps"
    }, {
        ID: 13,
        Assignee: "Mr. Robert Reagan",
        Subject: "Approval on Converting to New HDMI Specification"
    }, {
        ID: 14,
        Assignee: "Ms. Greta Sims",
        Subject: "Approve Hiring of John Jeffers"
    }, {
        ID: 15,
        Assignee: "Ms. Greta Sims",
        Subject: "Update Employee Files with New NDA"
    }, {
        ID: 16,
        Assignee: "Ms. Greta Sims",
        Subject: "Provide New Health Insurance Docs"
    }
];
Angular
app.component.html
app.module.ts
app.component.ts
app.service.ts
<dx-autocomplete
    [dataSource]="employeesTasks"
    valueExpr="Subject"
>
</dx-autocomplete>
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import { DxAutocompleteModule } from 'devextreme-angular';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        DxAutocompleteModule
    ],
    providers: [ ],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { Component } from '@angular/core';
import { Service, Task } from './app.service';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    providers: [Service]
})
export class AppComponent {
    employeesTasks: Task[];
    constructor(service: Service) {
        this.employeesTasks = service.getTasks();
    }
}
import { Injectable } from '@angular/core';

export class Task {
    ID: number | undefined;
    Assignee: string | undefined;
    Subject: string | undefined;
    disabled?: boolean | undefined;
}

const employeesTasks: Task[] = [
    {
        ID: 1,
        Assignee: "Mr. John Heart",
        Subject: "Choose between PPO and HMO Health Plan",
        disabled: true
    }, {
        ID: 2,
        Assignee: "Mr. John Heart",
        Subject: "Google AdWords Strategy"
    }, {
        ID: 3,
        Assignee: "Mr. John Heart",
        Subject: "New Brochures"
    }, {
        ID: 4,
        Assignee: "Mr. John Heart",
        Subject: "Update NDA Agreement"
    }, {
        ID: 5,
        Assignee: "Mr. John Heart",
        Subject: "Review Product Recall Report by Engineering Team"
    }, {
        ID: 6,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Update Personnel Files"
    }, {
        ID: 7,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Review Health Insurance Options Under the Affordable Care Act"
    }, {
        ID: 8,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Non-Compete Agreements"
    }, {
        ID: 9,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Give Final Approval for Refunds"
    }, {
        ID: 10,
        Assignee: "Mr. Robert Reagan",
        Subject: "Deliver R&D Plans for 2013"
    }, {
        ID: 11,
        Assignee: "Mr. Robert Reagan",
        Subject: "Decide on Mobile Devices to Use in the Field"
    }, {
        ID: 12,
        Assignee: "Mr. Robert Reagan",
        Subject: "Try New Touch-Enabled WinForms Apps"
    }, {
        ID: 13,
        Assignee: "Mr. Robert Reagan",
        Subject: "Approval on Converting to New HDMI Specification"
    }, {
        ID: 14,
        Assignee: "Ms. Greta Sims",
        Subject: "Approve Hiring of John Jeffers"
    }, {
        ID: 15,
        Assignee: "Ms. Greta Sims",
        Subject: "Update Employee Files with New NDA"
    }, {
        ID: 16,
        Assignee: "Ms. Greta Sims",
        Subject: "Provide New Health Insurance Docs"
    }
];

@Injectable()
export class Service {
    getTasks(): Task[] {
        return employeesTasks;
    }
}
Vue
App.vue
data.js
<template>
    <DxAutocomplete 
        :data-source="employeesTasks"
        value-expr="Subject"
    />

</template>

<script>
import 'devextreme/dist/css/dx.light.css';
import { DxAutocomplete } from 'devextreme-vue/autocomplete';
import { employeesTasks } from './data.js';

export default {
    components: {
        DxAutocomplete
    },
    data() {
        return {
            employeesTasks
        }
    }
}
</script>
export const employeesTasks = [
    {
        ID: 1,
        Assignee: "Mr. John Heart",
        Subject: "Choose between PPO and HMO Health Plan",
        disabled: true
    }, {
        ID: 2,
        Assignee: "Mr. John Heart",
        Subject: "Google AdWords Strategy"
    }, {
        ID: 3,
        Assignee: "Mr. John Heart",
        Subject: "New Brochures"
    }, {
        ID: 4,
        Assignee: "Mr. John Heart",
        Subject: "Update NDA Agreement"
    }, {
        ID: 5,
        Assignee: "Mr. John Heart",
        Subject: "Review Product Recall Report by Engineering Team"
    }, {
        ID: 6,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Update Personnel Files"
    }, {
        ID: 7,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Review Health Insurance Options Under the Affordable Care Act"
    }, {
        ID: 8,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Non-Compete Agreements"
    }, {
        ID: 9,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Give Final Approval for Refunds"
    }, {
        ID: 10,
        Assignee: "Mr. Robert Reagan",
        Subject: "Deliver R&D Plans for 2013"
    }, {
        ID: 11,
        Assignee: "Mr. Robert Reagan",
        Subject: "Decide on Mobile Devices to Use in the Field"
    }, {
        ID: 12,
        Assignee: "Mr. Robert Reagan",
        Subject: "Try New Touch-Enabled WinForms Apps"
    }, {
        ID: 13,
        Assignee: "Mr. Robert Reagan",
        Subject: "Approval on Converting to New HDMI Specification"
    }, {
        ID: 14,
        Assignee: "Ms. Greta Sims",
        Subject: "Approve Hiring of John Jeffers"
    }, {
        ID: 15,
        Assignee: "Ms. Greta Sims",
        Subject: "Update Employee Files with New NDA"
    }, {
        ID: 16,
        Assignee: "Ms. Greta Sims",
        Subject: "Provide New Health Insurance Docs"
    }
];
React
App.js
data.js
import 'devextreme/dist/css/dx.light.css';
import { employeesTasks } from './data';
import { Autocomplete } from 'devextreme-react';

function App() {
    return (
        <Autocomplete
            dataSource={employeesTasks}
            valueExpr="Subject"
        />
    );
}

export default App;
export const employeesTasks = [
    {
        ID: 1,
        Assignee: "Mr. John Heart",
        Subject: "Choose between PPO and HMO Health Plan",
        disabled: true
    }, {
        ID: 2,
        Assignee: "Mr. John Heart",
        Subject: "Google AdWords Strategy"
    }, {
        ID: 3,
        Assignee: "Mr. John Heart",
        Subject: "New Brochures"
    }, {
        ID: 4,
        Assignee: "Mr. John Heart",
        Subject: "Update NDA Agreement"
    }, {
        ID: 5,
        Assignee: "Mr. John Heart",
        Subject: "Review Product Recall Report by Engineering Team"
    }, {
        ID: 6,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Update Personnel Files"
    }, {
        ID: 7,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Review Health Insurance Options Under the Affordable Care Act"
    }, {
        ID: 8,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Non-Compete Agreements"
    }, {
        ID: 9,
        Assignee: "Mrs. Olivia Peyton",
        Subject: "Give Final Approval for Refunds"
    }, {
        ID: 10,
        Assignee: "Mr. Robert Reagan",
        Subject: "Deliver R&D Plans for 2013"
    }, {
        ID: 11,
        Assignee: "Mr. Robert Reagan",
        Subject: "Decide on Mobile Devices to Use in the Field"
    }, {
        ID: 12,
        Assignee: "Mr. Robert Reagan",
        Subject: "Try New Touch-Enabled WinForms Apps"
    }, {
        ID: 13,
        Assignee: "Mr. Robert Reagan",
        Subject: "Approval on Converting to New HDMI Specification"
    }, {
        ID: 14,
        Assignee: "Ms. Greta Sims",
        Subject: "Approve Hiring of John Jeffers"
    }, {
        ID: 15,
        Assignee: "Ms. Greta Sims",
        Subject: "Update Employee Files with New NDA"
    }, {
        ID: 16,
        Assignee: "Ms. Greta Sims",
        Subject: "Provide New Health Insurance Docs"
    }
];

Group Data

You can group data items in the Autocomplete drop-down list.

If the data source contains ungrouped data items, use the DataSource's group property to specify the data field by which to group.

The component can also work with initially grouped data items. In this case, the data array should contain objects with the key and items fields:

let dataSource = [{
    key: "Group 1", // Group caption 
    items: [ // Items in Group 1
        { /* ... */ },
        { /* ... */ }
    ]
}, {
    key: "Group 2",
    items: [
        { /* ... */ },
        { /* ... */ }
    ]
}];

If data objects are grouped but use other field names, implement the map function of the DataSource's group to create key and items field mappings.

NOTE
Only one-level grouping is supported.

Regardless of the data source structure, enable the grouped property.

The following code example groups the data source by the Assignee field and supplies it to the component:

jQuery
index.js
$(function() {
    const dataSource = new DevExpress.data.DataSource({
        store: {
            type: 'array',
            data: employeesTasks,
            key: 'ID',
        },
        group: 'Assignee',
    });

    $("#autocomplete").dxAutocomplete({
        dataSource,
        valueExpr: "Subject",
        grouped: true
    });
});
Angular
app.component.html
app.component.ts
<dx-autocomplete
    [dataSource]="dataSource"
    valueExpr="Subject"
    [grouped]="true"
>
</dx-autocomplete>
// ...
import DataSource from 'devextreme/data/data_source';
import ArrayStore from 'devextreme/data/array_store';

// ...
export class AppComponent {
    employeesTasks: Task[];
    dataSource: any;

    constructor(service: Service) {
        this.employeesTasks = service.getTasks();
        this.dataSource = new DataSource({
            store: new ArrayStore({
                data: this.employeesTasks,
                key: "ID"
            }),
            group: "Assignee"
        });

    }
}
Vue
App.vue
<template>
    <DxAutocomplete 
        :data-source="dataSource"
        value-expr="Subject"
        :grouped="true"
    >
    </DxAutocomplete>
</template>

<script>
// ...
import DataSource from 'devextreme/data/data_source';

export default {
    components: {
        DxAutocomplete
    },
    data() {
        return {
            dataSource: new DataSource({
                store: {
                    type: 'array',
                    data: employeesTasks,
                    key: 'ID',
                },
                group: 'Assignee',
            }),
        }
    }
}
</script>
React
App.js
// ...
import DataSource from 'devextreme/data/data_source';

function App() {
    const dataSource = new DataSource({
        store: {
            type: 'array',
            data: employeesTasks,
            key: 'ID',
        },
        group: 'Assignee',
    });

    return (
        <Autocomplete
            dataSource={dataSource}
            valueExpr="Subject"
            grouped={true}
        >
        </Autocomplete>
    );
}

export default App;

Configure Search Settings

Usually, the data field that supplies Autocomplete with suggestions (valueExpr) is the same data field where users search text. If you use two different fields, do the following:

  • Assign the field that supplies Autocomplete with suggestions to the valueExpr property.
  • Assign the field for search queries to the searchExpr property.

Note that searchExpr also accepts arrays if you want to search by multiple fields.

The Autocomplete component can supply suggestions in two different modes: 'contains' (default) and 'startswith'. You can use the searchMode property to change the mode.

When a user types the first character, Autocomplete displays suggestions. To increase the minimum number of typed characters, use the minSearchLength property. To limit the maximum number of characters that a user can type in, use the maxLength property. You can also specify the time interval before the Autocomplete component displays a suggestion after user input. Assign this time interval in milliseconds to the searchTimeout property.

The following code example specifies the searchTimeout and maxLength properties:

jQuery
index.js
$(function() {
    // ...

    $("#autocomplete").dxAutocomplete({
        // ...
        searchTimeout: 300,
        maxLength: 20
    });
});
Angular
app.component.html
<dx-autocomplete ...
    [searchTimeout]="300"
    [maxLength]="20"
>
</dx-autocomplete>
Vue
App.vue
<template>
    <DxAutocomplete ...
        :search-timeout="300"
        :max-length="20"
    >
    </DxAutocomplete>
</template>

<script>
// ...
</script>
React
App.js
// ...

function App() {
    // ...
    return (
        <Autocomplete ...
            searchTimeout={300}
            maxLength={20}
        >
        </Autocomplete>
    );
}

export default App;

Customize Field Appearance

Specify the height and width properties to change the size of the Autocomplete text field. If you want to resize the drop-down list, use the dropDownOptions object.

To specify one of the predefined styles for the Autocomplete text field, use the stylingMode property.

Use the placeholder property to give users a hint about what they should type in the Autocomplete text field. You can also use the label property for this purpose. If you specify the label property, set the labelMode property to one of the following values:

  • "static"
    The component displays the label above the input field.

  • "floating"
    The component uses the label as a placeholder, but when the editor gets focus, the label moves to the position above the input field.

  • "hidden"
    The label is hidden.

In this tutorial, the component also uses the label as a placeholder, because the labelMode property is set to "floating".

Additionally, Autocomplete can display the following buttons:

jQuery
index.js
$(function() {
    // ...

    $("#autocomplete").dxAutocomplete({
        // ...
        label: "Search for a task",
        labelMode: "floating",
        showClearButton: true
    });
});
Angular
app.component.html
<dx-autocomplete ...
    label="Search for a task"
    labelMode="floating"
    [showClearButton]="true"
>
</dx-autocomplete>
Vue
App.vue
<template>
    <DxAutocomplete ...
        label="Search for a task"
        label-mode="floating"
        :show-clear-button="true"
    >
    </DxAutocomplete>
</template>

<script>
// ...
</script>
React
App.js
// ...

function App() {
    // ...
    return (
        <Autocomplete ...
            label="Search for a task"
            labelMode="floating"
            showClearButton={true}
        >
        </Autocomplete>
    );
}

export default App;

Customize Item Appearance

jQuery

To customize the appearance of all Autocomplete suggestions, define an item template.

If your data is grouped, you may want to customize the group headings. Define a group template for that purpose.

You can also enable wrapItemText to wrap the text if the item's text exceeds the width of the drop-down list.

index.js
$(function() {
    // ...

    $("#autocomplete").dxAutocomplete({
        // ...
        groupTemplate ({ key }) {
            return "Assigned to " + key;
        },
        itemTemplate ({ Subject }, index) {
            return index + 1 + '. ' + Subject;
        },
        wrapItemText: true
    });
});
Angular

To customize the appearance of all Autocomplete suggestions, define an item template. To customize an individual suggestion, use custom templates property.

If your data is grouped, you may want to customize the group headings. Define a group template for that purpose.

You can also enable wrapItemText to wrap the text if the item's text exceeds the width of the drop-down list.

app.component.html
<dx-autocomplete ...
    groupTemplate="group"
    itemTemplate="item"
    [wrapItemText]="true"
>
    <div *dxTemplate="let data of 'group'">
        {{ "Assigned to " + data.key }}
    </div>
    <div *dxTemplate="let item of 'item', let index=index">
        {{ index + 1 + ". " + item.Subject }}
    </div>
</dx-autocomplete>
Vue

To customize the appearance of all Autocomplete suggestions, define an item template. To customize an individual suggestion, use custom templates property.

If your data is grouped, you may want to customize the group headings. Define a group template for that purpose.

You can also enable wrapItemText to wrap the text if the item's text exceeds the width of the drop-down list.

App.vue
<template>
    <DxAutocomplete ...
        :wrap-item-text="true"
        group-template="group"
        item-template="item"
    >
        <template #group="{data}">
            {{ "Assigned to " + data.key }}
        </template>
        <template #item="{data, index}">
            {{ index + 1 + ". " + data.Subject }}
        </template>
    </DxAutocomplete>
</template>

<script>
// ...
</script>
React

To customize the appearance of all Autocomplete suggestions, implement the itemRender or itemComponent function. To customize an individual suggestion, specify the render or component property.

If your data is grouped, you may want to customize the group headings. Implement the groupRender or groupComponent function for that purpose.

You can also enable wrapItemText to wrap the text if the item's text exceeds the width of the drop-down list.

App.js
// ...

const groupRender = (e) => {
    return "Assigned to " + e.key;
}

const itemRender = (e, index) => {
    return index + 1 + ". " + e.Subject;
}

function App() { 
    // ...

    return (
        <Autocomplete ...
            groupRender={groupRender}
            itemRender={itemRender}
            wrapItemText={true}
        />
    );
}

export default App;

Handle Value Change

Implement the onValueChanged handler to perform an action when a user selects an item or types in the Autocomplete text field. In the code example below, this function logs previous and new values in the console.

jQuery
index.js
$(function() {
    // ...

    $("#autocomplete").dxAutocomplete({
        // ...
        onValueChanged: function(e) {
            console.log(e.value);
            console.log(e.previousValue);
        },
    });
});
Angular
app.component.html
app.component.ts
<dx-autocomplete ...
    (onValueChanged)="onValueChanged($event)">
</dx-autocomplete>
// ...

export class AppComponent {
    // ...
    onValueChanged(e) {
        console.log(e.previousValue);
        console.log(e.value);
    }
}
Vue
App.vue
<template>
    <DxAutocomplete ...
        @value-changed="onValueChanged"
    />
</template>

<script>
export default {
    // ...
    methods: {
        onValueChanged(e) {
            console.log(e.previousValue);
            console.log(e.value);
        }
    }
}
</script>
React
App.js
// ...
import React, { useCallback } from 'react';

function App() { 
    // ...
    const onValueChanged = useCallback((e) => {
        console.log(e.previousValue);
        console.log(e.value);
    }, []);

    return (
        <Autocomplete ...
            onValueChanged={onValueChanged}
        />
    );
}

export default App;