Material Components (MDC) help developers implement Material Design. Created by a team of engineers and UX designers at Google, MDC features dozens of beautiful and functional UI components and is available for Android, iOS, web and Flutter.

material.io/develop

Material Components for the web (MDC Web) are framework-agnostic, built using regular JavaScript. This helps make MDC Web work seamlessly with your development process. These components can be installed as needed to help make agile design improvements in your existing app.

What you'll build

In this codelab, you'll replace some existing components in a form with ones provided by MDC Web:

MDC Web components in this codelab

What you'll need

How would you rate your level of experience with web development?

Novice Intermediate Proficient

Download the starter codelab app

Download starter app

The starter app is located in the material-components-web-codelabs-master/mdc-111/starter directory. Be sure to cd into that directory before you start.

...or clone it from GitHub

To clone this codelab from GitHub, run the following commands:

git clone https://github.com/material-components/material-components-web-codelabs
cd material-components-web-codelabs/mdc-111/starter

Install project dependencies

From the starter directory (material-components-web-codelabs/mdc-111/starter), run:

npm install

You will see a lot of activity and at the end, your terminal should show a successful install:

Run the starter app

In the starter directory, run:

npm start

The webpack-dev-server will start. Point your browser to http://localhost:8080/ to see the page.

Success! You should see the app's shipping address form:

Install MDC Button

Press Ctrl+C to kill the development server. Then, install the MDC Button NPM package and restart the server:

npm install @material/button@0.35.0
npm start

Import the CSS

At the top of _theme.scss, delete the .crane-button { ... } block, and add the following in its place:

$mdc-theme-primary: $crane-primary-color;

@import "@material/button/mdc-button";

Update the markup

In index.html, add the mdc-button and mdc-button--raised classes to the <button> element:

<button type="submit" class="crane-button mdc-button mdc-button--raised">Save</button>

Add the ripple

MDC Buttons can be used without JavaScript. However, adding an interactive ripple to the button creates a richer user experience.

Add the following import statement to the top of app.js:

import {MDCRipple} from '@material/ripple';

To instantiate the ripple on the button, add the following to the bottom of app.js:

new MDCRipple(document.querySelector('.mdc-button'));

Import Roboto font

By default, Material Design uses Roboto for component typefaces.

In index.html, import the Roboto Web font by adding the following to the <head> element:

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700">

Reload the page, and you should see something like this:

The button now displays subtle ripple effect as visual feedback when pressed.

The MDC Select component wraps a native HTML <select> element. Use it wherever you would normally use a <select>. Let's update the "State" field.

Install MDC Node module

Press Ctrl+C to kill the development server. Then run:

npm install @material/select@0.35.0
npm start

Import the CSS

Add the following to _theme.scss, just after the button import:

@import "@material/select/mdc-select";

Update markup

Locate the <select> element in index.html. Replace the crane-input class with crane-select__native-control and mdc-select__native-control:

<select class="crane-select__native-control mdc-select__native-control" id="crane-state-input" required>

Just below the closing </select> tag, replace the crane-label class with crane-select__label and mdc-select__label:

<label class="crane-select__label mdc-floating-label" for="crane-state-input">

Then add the following markup immediately after the label:

<div class="mdc-line-ripple"></div>

Finally, wrap the contents of the crane-field element with:

<div class="crane-select mdc-select mdc-select--box">
  ...
</div>

The resulting markup should look like this:

<div class="crane-field">
  <div class="crane-select mdc-select mdc-select--box">
    <select class="crane-select__native-control mdc-select__native-control" id="crane-state-input" required>
      <option value="" selected></option>
      <option value="AL">Alabama</option>
      ...
      <option value="WI">Wisconsin</option>
      <option value="WY">Wyoming</option>
    </select>
    <label class="crane-select__label mdc-floating-label" for="crane-state-input">
      State
    </label>
    <div class="mdc-line-ripple"></div>
  </div>
</div>

Import the JS

Add the following import statement to the top of app.js:

import {MDCSelect} from '@material/select';

To instantiate the select, add the following to the bottom of app.js:

new MDCSelect(document.querySelector('.mdc-select'));

Reload the page, which should now look like this:

The MDC Select component presents a list of options for the user in a familiar format, but with modern styling.

Material Design text fields have major usability gains over plain <input> elements. They are designed to be easy to identify within complicated content, and display subtle visual feedback when the user interacts with them.

Install MDC Node module

Press Ctrl+C to kill the development server. Then run:

npm install @material/textfield@0.35.0
npm start

Add the CSS

Add the following to _theme.scss, just after the select import:

@import "@material/textfield/mdc-text-field";

.crane-text-field {
  margin: 0;
}

Update the markup

In index.html, locate the <input> element for the "Name" field. Replace the crane-input class with crane-text-field__input and mdc-text-field__input:

<input class="crane-text-field__input mdc-text-field__input" id="crane-name-input" type="text" required>

Next, replace the crane-label class with crane-floating-label and mdc-floating-label:

<label class="crane-floating-label mdc-floating-label" for="crane-name-input">

Then add the following markup immediately after the label:

<div class="mdc-line-ripple"></div>

Finally, wrap the contents of the crane-field element with:

<div class="crane-text-field mdc-text-field mdc-text-field--box">
  ...
</div>

The resulting markup should look like this:

<div class="crane-field">
  <div class="crane-text-field mdc-text-field mdc-text-field--box">
    <input class="crane-text-field__input mdc-text-field__input" id="crane-name-input"
           type="text" required autofocus>
    <label class="crane-floating-label mdc-floating-label" for="crane-name-input">
      Name
    </label>
    <div class="mdc-line-ripple"></div>
  </div>
</div>

Repeat the same procedure for all other <input> elements on the page.

The markup for the "Address", "City" and "ZIP Code" fields should look like this:

<div class="crane-field">
  <div class="crane-text-field mdc-text-field mdc-text-field--box">
    <input class="crane-text-field__input mdc-text-field__input" id="crane-address-input" type="text" required>
    <label class="crane-floating-label mdc-floating-label" for="crane-address-input">
      Address
    </label>
    <div class="mdc-line-ripple"></div>
  </div>
</div>
<div class="crane-field">
  <div class="crane-text-field mdc-text-field mdc-text-field--box">
    <input class="crane-text-field__input mdc-text-field__input" id="crane-city-input" type="text" required>
    <label class="crane-floating-label mdc-floating-label" for="crane-city-input">
      City
    </label>
    <div class="mdc-line-ripple"></div>
  </div>
</div>
<div class="crane-field">
  <div class="crane-text-field mdc-text-field mdc-text-field--box">
    <input class="crane-text-field__input mdc-text-field__input" id="crane-zip-code-input"
            type="text" required minlength="5" maxlength="5" pattern="[0-9]*">
    <label class="crane-floating-label mdc-floating-label" for="crane-zip-code-input">
      ZIP Code
    </label>
    <div class="mdc-line-ripple"></div>
  </div>
</div>

Import the JS

Add the following import statement to the top of app.js:

import {MDCTextField} from '@material/textfield';

To instantiate the text fields, add the following to the bottom of app.js:

const textFieldElements = [].slice.call(document.querySelectorAll('.mdc-text-field'));
textFieldElements.forEach((textFieldEl) => {
  new MDCTextField(textFieldEl);
});

Reload the page, which should now look like this:

The text fields have now all been updated to use Material Theming.

You've replaced some common components (text fields, select, and button) without doing a complete redesign of your app. Great job!

Other components that can also make a big difference include the top app bar and navigation drawer.

Next steps

You can explore even more components in MDC Web by visiting the MDC Web catalog.

If you are interested in using MDC Web with a particular framework, head over to MDC-112: Integrating MDC with Web Frameworks.

I was able to complete this codelab with a reasonable amount of time and effort

Strongly agree Agree Neutral Disagree Strongly disagree

I would like to continue using Material Components in the future

Strongly agree Agree Neutral Disagree Strongly disagree