MDC-101 Web: Material Components (MDC) Basics (Web)

1. Introduction

logo_components_color_2x_web_96dp.png

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

What are Material Design and Material Components for the Web?

Material Design is a system for building bold and beautiful digital products. By uniting style, branding, interaction, and motion under a consistent set of principles and components, product teams can realize their greatest design potential.

For desktop and the mobile web, Material Components Web (MDC Web) unites design and engineering with a library of components for creating consistency across apps and websites. MDC Web components each live in their own node modules, so as the Material Design system evolves, these components can be easily updated to ensure consistent pixel-perfect implementation and adherence to Google's front-end development standards. MDC is also available for Android, iOS, and Flutter.

In this codelab, you'll build a login page using several of MDC Web's components.

What you'll build

This codelab is the first of three codelabs that will guide you through building an app called Shrine, an e-commerce website that sells clothing and home goods. It will demonstrate how you can customize components to reflect any brand or style using MDC Web.

In this codelab, you'll build a login page for Shrine that contains:

  • Two text fields, one for entering a username and the other for a password
  • Two buttons, one for "Cancel" and one for "Next"
  • The name of the website (Shrine)
  • An image of Shrine's logo

674d1ca8cfa98c9.png

MDC Web components in this codelab

  • Text field
  • Button
  • Ripple

What you'll need

  • A recent version of Node.js (which comes bundled with npm, a JavaScript package manager).
  • The sample code (to be downloaded in the next step)
  • Basic knowledge of HTML, CSS, and JavaScript

We're always looking to improve our tutorials. How would you rate your level of experience with web development?

Novice Intermediate Proficient

2. Set up your development environment

Download the starter codelab app

The starter app is located within the material-components-web-codelabs-master/mdc-101/starter directory. Be sure to cd into that directory before beginning.

...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-101/starter

Install project dependencies

From the starter directory, run:

npm install

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

204c063d8fd78f94.png

If it doesn't, run npm audit fix.

Run the starter app

In the same directory, run:

npm start

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

17c139dc5a9bebaf.png

Success! The starter code for Shrine's login page should be running in your browser. You should see the name "Shrine" and the Shrine logo just below it.

f7e3f354df8d84b8.png

Take a look at the code

Metadata in index.html

In the starter directory, open index.html with your favorite code editor. It should contain this:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <title>Shrine (MDC Web Example App)</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" sizes="192x192" href="https://material.io/static/images/simple-lp/favicons/components-192x192.png">
  <link rel="shortcut icon" href="https://material.io/static/images/simple-lp/favicons/components-72x72.png">

  <link rel="stylesheet"
        href="https://cdnjs.cloudflare.com/ajax/libs/normalize/6.0.0/normalize.min.css">
  <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet">
  <link rel="stylesheet" href="bundle-login.css">
</head>
<body class="shrine-login">
  <section class="header">
    <svg class="shrine-logo" ...>
      ...
    </svg>
    <h1>SHRINE</h1>
  </section>

  <form action="home.html">
  </form>

  <script src="bundle-login.js" async></script>
</body>
</html>

Here, a <link> tag is used to load the bundle-login.css file which was generated by webpack, and a <script> tag includes the bundle-login.js file. In addition, we include normalize.css for consistent cross-browser rendering, as well as the Roboto font from Google Fonts.

Custom styles in login.scss

MDC Web components are styled using mdc-* CSS classes, such as the class mdc-text-field. (MDC Web treats its DOM structure as part of its public API.)

In general, it's recommended that you make custom style modifications to components using your own classes. You might have noticed some custom CSS classes in the HTML above, such as shrine-logo. These styles are defined in login.scss to add basic styles to the page.

Open login.scss and you'll see the following styles for the login page:

@import "./common";

.header {
  text-align: center;
}

.shrine-logo {
  width: 150px;
  height: 150px;
  padding-top: 80px;
  fill: currentColor;
}

Now that you're familiar with the starter code, let's implement our first component.

3. Add text fields

To begin, we'll add two text fields to our login page, where people will be able to enter their username and password. We'll use the MDC Text Field component, which includes built-in functionality that displays a floating label and activates a touch ripple.

9ad8a7db0b50f07d.png

Install the MDC Text Field

MDC Web components are published via NPM packages. To install the package for the text field component, run:

npm install @material/textfield@^6.0.0

Add the HTML

In index.html, add the following inside the <form> element in the body:

<label class="mdc-text-field mdc-text-field--filled username">
  <span class="mdc-text-field__ripple"></span>
  <input type="text" class="mdc-text-field__input" aria-labelledby="username-label" name="username">
  <span class="mdc-floating-label" id="username-label">Username</span>
  <span class="mdc-line-ripple"></span>
</label>
<label class="mdc-text-field mdc-text-field--filled password">
  <span class="mdc-text-field__ripple"></span>
  <input type="password" class="mdc-text-field__input" aria-labelledby="password-label" name="password">
  <span class="mdc-floating-label" id="password-label">Password</span>
  <span class="mdc-line-ripple"></span>
</label>

The MDC Text Field DOM structure is composed of several parts:

  • The main element, mdc-text-field
  • Subelements mdc-text-field__ripple, mdc-text-field__input, mdc-floating-label, and mdc-line-ripple

Add the CSS

In login.scss, add the following import statement after the existing import:

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

In the same file, add the following styles to align and center the text fields:

.username,
.password {
  display: flex;
  margin: 20px auto;
  width: 300px;
}

Add the JavaScript

Open up login.js, which is currently empty. Add the following code to import and instantiate the Text Fields:

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

const username = new MDCTextField(document.querySelector('.username'));
const password = new MDCTextField(document.querySelector('.password'));

Add HTML5 validation

Text Fields express if the field input is valid or contains an error, by using attributes provided by HTML5's form validation API.

You should:

  • Add the required attribute to the mdc-text-field__input elements of both the Username and Password text fields
  • Set the minlength attribute of the mdc-text-field__input element of the Password text field to "8"

Adjust the two <label class="mdc-text-field mdc-text-field--filled"> elements to look like this:

<label class="mdc-text-field mdc-text-field--filled username">
  <span class="mdc-text-field__ripple"></span>
  <input type="text" class="mdc-text-field__input" aria-labelledby="username-label" name="username" required>
  <span class="mdc-floating-label" id="username-label">Username</span>
  <span class="mdc-line-ripple"></span>
</label>
<label class="mdc-text-field mdc-text-field--filled password">
  <span class="mdc-text-field__ripple"></span>
  <input type="password" class="mdc-text-field__input" aria-labelledby="password-label" name="password" required minlength="8">
  <span class="mdc-floating-label" id="password-label">Password</span>
  <span class="mdc-line-ripple"></span>
</label>

Refresh the page at http://localhost:8080/. You should now see a page with two text fields for Username and Password!

Click on the text fields to check out the floating label animation and the line ripple animation (the bottom border line that ripples outwards):

c0b341e9949a6183.gif

4. Add buttons

Next, we'll add two buttons to our login page: "Cancel" and "Next." We'll use the MDC Button component, along with the MDC Ripple component, to complete the iconic Material Design ink ripple effect.

674d1ca8cfa98c9.png

Install MDC Button

To install the package for the button component, run:

npm install @material/button@^6.0.0

Add the HTML

In index.html, add the following below the closing tag of the <label class="mdc-text-field mdc-text-field--filled password"> element:

<div class="button-container">
  <button type="button" class="mdc-button cancel">
    <div class="mdc-button__ripple"></div>
    <span class="mdc-button__label">
      Cancel
    </span>
  </button>
  <button class="mdc-button mdc-button--raised next">
    <div class="mdc-button__ripple"></div>
    <span class="mdc-button__label">
      Next
    </span>
  </button>
</div>

For the "Cancel" button, we're using the default button style. However, the "Next" button uses a raised style variant, which is indicated by the mdc-button--raised class.

To easily align them later, we wrap the two mdc-button elements in a <div> element.

Add the CSS

In login.scss, add the following import statement after the existing imports:

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

To align the buttons and add a margin around them, add the following styles to login.scss:

.button-container {
  display: flex;
  justify-content: flex-end;
  width: 300px;
  margin: auto;
}

.button-container button {
  margin: 3px;
}

Add an ink ripple to the buttons

When the user touches or clicks a button, it should display feedback in the form of an ink ripple. The ink ripple component requires JavaScript, so we'll add that to the page.

To install the package for the ripple component, run:

npm install @material/ripple@^6.0.0

At the top of login.js, add the following import statement:

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

To instantiate the ripples, add the following to login.js:

new MDCRipple(document.querySelector('.cancel'));
new MDCRipple(document.querySelector('.next'));

Because we don't need to retain a reference to the ripple instance, there's no need to assign it to a variable.

That's it! Refresh the page. An ink ripple will display when you click each button.

bb19b0a567977bde.gif

Fill in the text fields with valid values, and press the "NEXT" button. You did it! You'll continue working on this page in MDC-102.

5. Recap

Using basic HTML markup and just a few lines of CSS and JavaScript, the Material Components for the web library has helped you create a beautiful login page that conforms to the Material Design guidelines, and looks and behaves consistently across all devices.

Next steps

Text Field, Button, and Ripple are three core components in the MDC Web library, but there are many more! You can also explore the rest of the components in MDC Web.

You can head over to MDC-102: Material Design Structure and Layout to learn about the navigation drawer and image list. Thanks for trying Material Components. We hope you enjoyed this codelab!

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