All Components

This website hosts native Kendo UI components, built from the ground up with the ultimate performance in mind, intended to be used in the React ecosystem.

ComboBox Overview

The ComboBox is a form component that lets you choose a single predefined value from a list.

It is a richer version of the <select> element and supports filtering, virtualization, and entering of custom values.

Basic Usage

The following example demonstrates the ComboBox in action.

import React from 'react';
import ReactDOM from 'react-dom';

import { ComboBox } from '@progress/kendo-react-dropdowns';

class AppComponent extends React.Component {
    sports = [ "Baseball", "Basketball", "Cricket", "Field Hockey", "Football", "Table Tennis", "Tennis", "Volleyball" ];

    constructor(props) {
        super(props);
        this.state = {
            allowCustom: true
        };

        this.onChange = this.onChange.bind(this);
    }

    onChange(event) {
        this.setState({
            allowCustom: event.target.checked
        });
    }

    render() {
        const allowCustom = this.state.allowCustom;
        return (
            <div className="example-wrapper">
                <div className="example-config">
                    <input id="ac" type="checkbox" className="k-checkbox" onChange={this.onChange} checked={allowCustom} />
                    <label className="k-checkbox-label" for="ac">Allow custom values</label>
                </div>
                <div>
                    <div>Favorite sport:</div>
                    <ComboBox data={this.sports} allowCustom={allowCustom} />
                </div>
            </div>
        );
    }
}

ReactDOM.render(
    <AppComponent />,
    document.querySelector('my-app')
);

Functionality and Features

Events

The following example demonstrates basic ComboBox events.

import React from 'react';
import ReactDOM from 'react-dom';
import { ComboBox } from '@progress/kendo-react-dropdowns';

class AppComponent extends React.Component {
    source = [ "Albania", "Andorra", "Armenia", "Austria", "Azerbaijan" ];

    constructor(props) {
        super(props);

        this.state = {
            events: []
        };

        this.onOpen = this.onOpen.bind(this);
        this.onClose = this.onClose.bind(this);
        this.onFocus = this.onFocus.bind(this);
        this.onBlur = this.onBlur.bind(this);
        this.onChange = this.onChange.bind(this);
        this.onFilterChange = this.onFilterChange.bind(this);
    }

    onOpen() { this.log('open'); }
    onClose() { this.log('close'); }
    onFocus() { this.log('focus'); }
    onBlur() { this.log('blur'); }
    onChange(event) { this.log('change', event.target.value); }
    onFilterChange(event) { this.log('filterChange', event.filter.value); }

    render() {
        return (
            <div>
                <ComboBox
                    data={this.source}
                    onOpen={this.onOpen}
                    onClose={this.onClose}
                    onFocus={this.onFocus}
                    onBlur={this.onBlur}
                    onChange={this.onChange}
                    onFilterChange={this.onFilterChange}
                    filterable={true}
                />
                <br />
                <br />
                <EventsLogger events={this.state.events} />
            </div>
        );
    }

    log(event, arg) {
        const events = this.state.events;
        events.unshift(`${event} ${arg || ""}`);

        this.setState({
            events: events
        });
    }
}

class EventsLogger extends React.Component {
    render() {
        return (
            <div class="example-config">
                <h5>Event log</h5>
                <ul class="event-log" style={{ textAlign: 'right' }}>
                    {this.props.events.map(function(event, index) {
                        return (<li key={index}>{event}</li>);
                    })}
                </ul>
            </div>
        );
    }
}

ReactDOM.render(
    <AppComponent />,
    document.querySelector('my-app')
);

Common Scenarios

You can use the configuration options of the ComboBox to achieve the implementation of common scenarios such as:

Implementing Cascading ComboBoxes

The cascading ComboBox is a series of two or more ComboBoxes where each ComboBox is filtered based on the selected option in the previous ComboBox.

import React from 'react';
import ReactDOM from 'react-dom';
import { ComboBox } from '@progress/kendo-react-dropdowns';
import { dataCategories, dataProducts, dataOrders } from './data.js';

class AppComponent extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            category: null,
            product: null,
            order: null,
            orders: dataOrders,
            products: dataProducts
        };

        this.categoryChange = this.categoryChange.bind(this);
        this.productChange = this.productChange.bind(this);
        this.orderChange = this.orderChange.bind(this);
    }

    categoryChange(event) {
        const category = event.target.value;
        const products = category && dataProducts.filter(product => product.categoryId === category.categoryId);

        this.setState({
            category: category,
            products: products,
            product: null,
            order: null
        });
    }

    productChange(event) {
        const product = event.target.value;
        const orders = product && dataOrders.filter(order => order.productId === product.productId);

        this.setState({
            product: product,
            orders: orders,
            order: null
        });
    }

    orderChange(event) {
        this.setState({ order: event.target.value });
    }

    render() {
        const category = this.state.category;
        const product = this.state.product;
        const order = this.state.order;

        const hasCategory = category;
        const hasProduct = product;

        return (
            <div>
                <div style={{ display: 'inline-block' }}>
                    Categories
                    <br />
                    <ComboBox
                        data={dataCategories}
                        textField={'categoryName'}
                        onChange={this.categoryChange}
                        placeholder={'Select Category ...'}
                        value={category}
                    />
                </div>
                <div style={{ display: 'inline-block', marginLeft: '30px' }}>
                    Products
                    <br />
                    <ComboBox
                        disabled={!hasCategory}
                        data={this.state.products}
                        textField={'productName'}
                        onChange={this.productChange}
                        placeholder={'Select Product ...'}
                        value={product}
                    />
                </div>
                <div style={{ display: 'inline-block', marginLeft: '30px' }}>
                    Orders
                    <br />
                    <ComboBox
                        disabled={!hasProduct}
                        data={this.state.orders}
                        textField={'orderName'}
                        onChange={this.orderChange}
                        placeholder={'Select Order ...'}
                        value={order}
                    />
                </div>
            </div>
        );
    }
}

ReactDOM.render(
    <AppComponent />,
    document.querySelector('my-app')
);
const dataCategories = [
    { categoryName: "Beverages", categoryId: 1 },
    { categoryName: "Condiments", categoryId: 2 },
    { categoryName: "Seafood", categoryId: 3 }
];

const dataProducts = [
    { productName: "Chai", productId: 1, categoryId: 1 },
    { productName: "Chang", productId: 2, categoryId: 1 },
    { productName: "Aniseed Syrup", productId: 3, categoryId: 2 },
    { productName: "Genen Shouyu", productId: 4, categoryId: 2 },
    { productName: "Ikura", productId: 5, categoryId: 3 },
    { productName: "Konbu", productId: 6, categoryId: 3 }
];

const dataOrders = [
    { orderName: "Cunewalde", orderId: 1, productId: 1 },
    { orderName: "Albuquerque", orderId: 2, productId: 1 },
    { orderName: "Geneva", orderId: 3, productId: 2 },
    { orderName: "Graz", orderId: 4, productId: 2 },
    { orderName: "London", orderId: 5, productId: 3 },
    { orderName: "I. de Margarita", orderId: 6, productId: 3 },
    { orderName: "Barquisimeto", orderId: 7, productId: 4 },
    { orderName: "Brandenburg", orderId: 8, productId: 4 },
    { orderName: "Cunewalde", orderId: 9, productId: 5 },
    { orderName: "Mexico D.F.", orderId: 10, productId: 5 },
    { orderName: "Mexico D.F.", orderId: 11, productId: 6 },
    { orderName: "Rio de Janeiro", orderId: 12, productId: 6 }
];

export { dataCategories, dataProducts, dataOrders };

Using Remote Data with Virtualization and Filtering

The following example demonstrates how to configure the ComboBox to use remote data along with data caching, virtual scrolling, and filtering.

import React from 'react';
import ReactDOM from 'react-dom';
import { ComboBox } from '@progress/kendo-react-dropdowns';

const textField = 'ContactName';
const valueField = 'CustomerID';
const pageSize = 9;

let counter = 0;
const emptyItem = function() {
    return {
        [textField]: 'loading ...',
        [valueField]: (++counter).toString()
    };
};

const loadingData = [];
while (loadingData.length < pageSize) {
    loadingData.push({ ...emptyItem() });
}

class AppComponent extends React.Component {
    baseUrl = `https://odatasampleservices.azurewebsites.net/V4/Northwind/Northwind.svc/`;
    init = { method: 'GET', accept: 'application/json', headers: [] };
    dataCaching = [];
    pendingRequest;
    requestStarted = false;

    constructor(props) {
        super(props);

        this.state = {
            data: [],
            skip: 0,
            total: 0,
            filter: ''
        };
    }

    componentDidMount() {
        this.requestData(0, this.state.filter);
    }

    requestData(skip, filter) {
        if (this.requestStarted) {
            clearTimeout(this.pendingRequest);
            this.pendingRequest = setTimeout(() => { this.requestData(skip, filter); }, 50);
            return;
        }

        const url = this.baseUrl +
            `Customers?$filter=contains(ContactName,'${filter}')&$skip=${skip}&$top=${pageSize}&$count=true`;

        this.requestStarted = true;
        fetch(url, this.init)
            .then(response => response.json())
            .then(json => {
                const total = json['@odata.count'];
                const items = [];
                json.value.forEach((element, index) => {
                    const { CustomerID, ContactName } = element;
                    const item = { [valueField]: CustomerID, [textField]: ContactName };
                    items.push(item);
                    this.dataCaching[index + skip] = item;
                });

                if (skip === this.state.skip) {
                    this.setState({
                        data: items,
                        total: total
                    });
                }
                this.requestStarted = false;
            });
    }

    onFilterChange = (event) => {
        const filter = event.filter.value;

        this.resetCach();
        this.requestData(0, filter);

        this.setState({
            data: loadingData,
            skip: 0,
            filter: filter
        });
    }

    pageChange = (event) => {
        const skip = event.page.skip;
        const filter = this.state.filter;

        let makeRequest = false;
        for (let i = 0; i < pageSize; i++) {
            if (!this.dataCaching[skip + i]) {
                makeRequest = true;
                break;
            }
        }

        if (makeRequest) {
            this.requestData(skip, filter);
        }

        const data = this.getCachedData(skip);

        this.setState({
            data: data,
            skip: skip
        });
    }

    render() {
        return (
            <div>
                <p>Customers</p>
                <ComboBox
                    data={this.state.data}
                    valueField={valueField}
                    textField={textField}
                    placeholder={'Select customer'}
                    filterable={true}
                    filter={this.state.filter}
                    onFilterChange={this.onFilterChange}
                    virtual={{
                        pageSize: pageSize,
                        skip: this.state.skip,
                        total: this.state.total
                    }}
                    onPageChange={this.pageChange}
                />
            </div>
        );
    }

    componentWillUnmount() {
        this.resetCach();
    }

    getCachedData(skip) {
        const data = [];
        for (let i = 0; i < pageSize; i++) {
            data.push(this.dataCaching[i + skip] || { ...emptyItem() });
        }
        return data;
    }

    resetCach() {
        this.dataCaching.length = 0;
    }
}

ReactDOM.render(
    <AppComponent />,
    document.querySelector('my-app')
);
In this article