Tutorial - Create a React.js Auto-complete Search Box With Material-UI in < 100 Lines of Code - Part I

May 11, 2016

If you’re keeping up to date with Web technologies, and you do a lot of work on the front-end, you’re probably aware that the way we develop interfaces has changed.

This change is good and holds a lot of potential power for you as a developer (or aspiring developer).

Today, most Single Page Apps (blazingly fast apps built for the browser) are written by thinking and developing in components.

So I want to show you how I developed, and published, a React-based auto-complete search box that searches Youtube (and it only required 100 lines of customized code).

This auto-complete search box provides suggested search terms from Youtube as a user types. It also provides video search results after a user selects a search term.

Here’s how it behaves (and one version of how it can look):


Autocomplete Component


Admittedly, the scope of this component is limited and it’s not applicable to many other apps; however, it’s also simple enough to provide a short tutorial so that developers can get the basic idea.

One of the main ideas I’m trying to convey is that developing and open-sourcing a component doesn’t always mean you have to write something from scratch. A core tenet of good software development is reuse, so it behooves you to discover what you can reuse and refactor for your purposes.

Let me show you how I did that.

(PLEASE NOTE: It’s really challenging to try to teach others highly technical material, so if you don’t understand something please don’t get frustrated. Send me an email and I’ll try to clarify things as best I can!)

Discovering What You Can Reuse

Frequently, I like to theme apps using Material-UI, a collection of React components that follow Google’s Material-UI design system.

It makes designing and theming my apps a snap, so I use it to bootstrap prototypes and MVPs (Minimally Viable Products).

During my research, I discovered a premade component from Material-UI called auto-complete.


Material-UI Auto-complete

This component works great out of the box; however, I needed this component to provide automatically suggested search queries from Youtube as a user typed.

Material-UI’s auto-complete component obviously doesn’t do this out of the box, so I needed to figure out a way to tweak it for my needs.

The Docs

Fortunately, the auto-complete component from Material-UI was developed in a reusable fashion and I discovered its “dataSource” property. This property lets you provide an array of data sources that popuplate the list of suggestions as a user types.


Material-UI Auto-complete dataSource

This was exactly what I needed. Now all I needed was a way to:

a) scaffold a new React component

b) import the pre-made Material-UI auto-complete component

c) populate its dataSource attribute with suggested queries from Youtube as a user typed

d) share it with everyone

(Note: to bootstrap my own component I use the awesome NWB CLI tool. It’s a great tool for building isolated and reusable components you can share with the world.)


How to Instantly Publish Your Own React Component

Publish Your React Component book cover

Learn how to create and publish your own UI components on NPM, and share your code with the world.

Start learning the insanely popular React.js from Facebook now. If you're a seasoned or new developer, open-sourcing your own component is a great way to get recognized.

START PUBLISHING


Setting Things Up

After scaffolding my new component with NWB, I wrote some basic boilerplate and laid out the foundation as shown in the code snippet below.

I named my React component “MaterialUIAutocomplete”. Not the best name, but it will do for now.

Please note: I’m defining my component as an ES6 JavaScript class, and I’m writing ES6 (the modern version of JavaScript).


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, {Component} from 'react';
import { Autocomplete }   from 'material-ui';

class MaterialUIAutocomplete extends Component {
  constructor(props) {
    super(props);
    this.onUpdateInput = this.onUpdateInput.bind(this);
    this.state = {
      dataSource : [],
      inputValue : ''
    }
  }

  onUpdateInput(inputValue) {
  }

  render() {
    return <AutoComplete
            dataSource    = {this.state.dataSource}
            onUpdateInput = {this.onUpdateInput} />
  }
}

export default MaterialUIAutocomplete;


On lines 1 and 2, I’m importing React and the auto-complete component from Material-UI.

On line 18, I’m utilizing the auto-complete component from Material-UI and specifying its dataSource. I’m also specifying the onUpdateInput prop and callback which gets called whenever a user types.

Adding the Material-UI Wrapper

The latest version of Material-UI has changed a bit. The library requires you to wrap things using a MuiThemeProvider component which will make it easier to theme your applications or components.

Without too much explanation, notice the function and theming component I import on lines 3 and 4.

Also take note of how I wrap my component using “MuiThemeProvider”. Material-UI now requires this.


1
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
import React, {Component} from 'react';
import { Autocomplete }   from 'material-ui';
import getMuiTheme        from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider   from 'material-ui/styles/MuiThemeProvider';

class MaterialUIAutocomplete extends Component {
  constructor(props) {
    super(props);
    this.onUpdateInput = this.onUpdateInput.bind(this);
    this.state = {
      dataSource : [],
      inputValue : ''
    }
  }

  onUpdateInput(inputValue) {
  }

  render() {
    return <MuiThemeProvider muiTheme={getMuiTheme()}>
      <AutoComplete
        dataSource    = {this.state.dataSource}
        onUpdateInput = {this.onUpdateInput} />
      </MuiThemeProvider>
  }
}

export default MaterialUIAutocomplete;


There’s no real functionality yet. As a use types into the search box, nothing happens. We have more work to do.

Do note that we have some preliminary styling without adding a single line of CSS.


Dummy component snapshot 1 - no functionality

Using JSONP

The next step involves plugging in the logic to deal with characters typed into the search box by a user, and querying Youtube/Google for suggested search terms.

Take a look at the code below.


1
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
import React, {Component} from 'react';
import { Autocomplete }   from 'material-ui';
import getMuiTheme        from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider   from 'material-ui/styles/MuiThemeProvider';
import JSONP              from 'jsonp';

const googleAutoSuggestURL = `
  //suggestqueries.google.com/complete/search?client=youtube&ds=yt&q=`;

class MaterialUIAutocomplete extends Component {
  constructor(props) {
    super(props);
    this.onUpdateInput = this.onUpdateInput.bind(this);
    this.state = {
      dataSource : [],
      inputValue : ''
    }
  }

  onUpdateInput(inputValue) {
    const self = this;
    this.setState({
      inputValue: inputValue
    }, function() {
      self.performSearch();
    });
  }

  performSearch() {
    const
      self = this,
      url  = googleAutoSuggestURL + this.state.inputValue;

    if(this.state.inputValue !== '') {
      JSONP(url, function(error, data) {
        // handle results here
      });
    }
  }

  render() {
    return <MuiThemeProvider muiTheme={getMuiTheme()}>
      <AutoComplete
        dataSource    = {this.state.dataSource}
        onUpdateInput = {this.onUpdateInput} />
      </MuiThemeProvider
  }
}

export default MaterialUIAutocomplete;


First, I import the JSONP NPM module one line 5.

Then I define a constant titled googleAutoSuggestURL on line 7. When a user types into the search box, a cross-domain JSONP call to Youtube will need to get executed, and this is the standard Google URL (with the right query params) for that call.

JSONP stands for JSON With Padding. It’s basically a way of overriding the browser’s baked-in AJAX restrictions so that we can make an asynchronous HTTP call to a third-party domain.

onUpdateInput

On line 20, I’m specifying the guts of the onUpdateInput() function. The characters typed in by the user are passed as an argument to onUpdateInput().

Once I set the state of the component with the value of what the user has currently typed, I call a function titled performSearch().

performSearch()

In the performSearch() function on line 29, I make a JSONP call and pass it Google’s JSONP URL with the appropriate query paramters. Eventually, video search results will get returned that we can handle and display to the user.

Handling Suggested Terms from Youtube

After the component makes a JSONP call to Google, results will be returned. The component needs to take those results, handle them accordingly, and display them to the user.

Here’s the code I added to performSearch().


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  performSearch() {
    const
      self = this,
      url  = googleAutoSuggestURL + this.state.inputValue;

    if(this.state.inputValue !== '') {
      JSONP(url, function(error, data) {
        let searchResults, retrievedSearchTerms;

        if(error) return error;

        searchResults = data[1];

        retrievedSearchTerms = searchResults.map(function(result) {
          return result[0];
        });

        self.setState({
          dataSource: retrievedSearchTerms
        });
      });
    }
  }


In this function, results are retrieved from Google and I pluck the right values (line 14).

The suggested search values are then passed into the Material-UI auto-complete component by setting the dataSource attribute (line 18).

The resulting search box behaves like this. As I type the term “bitcoin”, suggested search terms are automatically provided by Youtube.


Dummy component snapshot 2 - successfully populating dropdown list

Getting Actual Video Search Results

So far, I’ve designed this component to retrieve suggested search terms from Youtube.

But after a suggested search term gets selected by a user, the component should go out and retrieve the actual video search results for that selected term (there will be many).

The component should display video search results to the user. Sort of like this:


Dummy component snapshot 3 - video search results

Not Done Yet

In Part II of this blog series, I demonstrate how to get actual video search results from Youtube, and how to define a public-facing API for this component.

Read Part II to see the additional code added to this component. Here is the finalized source code.


How to Instantly Publish Your Own React Component

Publish Your React Component book cover

Learn how to create and publish your own UI components on NPM, and share your code with the world.

Start learning the insanely popular React.js from Facebook now. If you're a seasoned or new developer, open-sourcing your own component is a great way to get recognized.

START PUBLISHING