Getting Started
Quick Start (CDN)
To try Material Components for the web with minimal setup, load the precompiled all-in-one CSS and JS bundles from unpkg:
<head>
<link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css" rel="stylesheet">
<script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
</head>
We also recommend using
xxxxxxxxxx
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
</head>
Then include MDC markup...
xxxxxxxxxx
<button class="mdc-button foo-button">
<div class="mdc-button__ripple"></div>
<span class="mdc-button__label">Button</span>
</button>
...and instantiate JavaScript:
xxxxxxxxxx
mdc.ripple.MDCRipple.attachTo(document.querySelector('.foo-button'));
Installing Locally
Material Components for the web can be installed locally using npm. It is available as a single all-in-one package:
xxxxxxxxxx
npm i material-components-web
...or as individual components:
xxxxxxxxxx
npm i @material/button @material/ripple
Each package provides precompiled CSS and JS under its dist folder. The precompiled JS is converted to UMD format and is consumable directly by browsers or within any workflow that expects to consume ES5. Referencing @material/foo within a Node.js context will automatically reference the precompiled JS under dist.
However, for optimal results, we recommend consuming MDC Web's ES2015 modules and Sass directly. This is outlined in the steps below.
Using MDC Web with Sass and ES2015
This section walks through how to
You can also see the final code and result in the
Note: This guide assumes you have Node.js and npm installed locally.
Step 1: Webpack with Sass
We’re going to use webpack-dev-server to demonstrate how webpack bundles our Sass and JavaScript. First, run npm init to create a package.json file. When complete, add the start property to the scripts section.
xxxxxxxxxx
{
"scripts": {
"start": "webpack serve"
}
}
You’ll need all of these Node dependencies:
webpack : Bundles Sass and JavaScriptwebpack-dev-server : Development serversass-loader : Webpack loader to preprocess Sass filessass : Sass compilercss-loader : Resolves CSS @import and url() pathsextract-loader : Extracts the CSS into a .css filefile-loader : Serves the .css file as a public URL
You can install all of them by running this command:
xxxxxxxxxx
npm install --save-dev webpack webpack-cli webpack-dev-server css-loader sass-loader sass extract-loader file-loader
In order to demonstrate how webpack bundles our Sass, you’ll need an index.html. This HTML file needs to include CSS. The CSS is generated by sass-loader, which compiles Sass files into CSS. The CSS is extracted into a .css file by extract-loader. Create this simple “hello world” index.html:
xxxxxxxxxx
<html>
<head>
<link rel="stylesheet" href="bundle.css">
</head>
<body>Hello World</body>
</html>
And create a simple Sass file called app.scss:
xxxxxxxxxx
body {
color: blue;
}
Then configure webpack to convert app.scss into bundle.css. For that you need a new webpack.config.js file:
module.exports = [{
entry: './app.scss',
output: {
// This is necessary for webpack to compile
// But we never use style-bundle.js
filename: 'style-bundle.js',
},
module: {
rules: [
{
test: /\.scss$/,
use: [
{
loader: 'file-loader',
options: {
name: 'bundle.css',
},
},
{ loader: 'extract-loader' },
{ loader: 'css-loader' },
{
loader: 'sass-loader',
options: {
// Prefer Dart Sass
implementation: require('sass'),
// See https://github.com/webpack-contrib/sass-loader/issues/804
webpackImporter: false,
},
},
]
}
]
},
}];
To test your webpack configuration, run:
xxxxxxxxxx
npm start
And open
Step 2: Include CSS for a component
Now that you have webpack configured to compile Sass into CSS, let's include the Sass files for the Material Design button. First, install the Node dependency:
xxxxxxxxxx
npm install @material/button
We need to tell our app.scss to import the Sass files for @material/button. We can also use Sass mixins to customize the button. Replace your “hello world” version of app.scss with this code:
xxxxxxxxxx
@use '@material/button/mdc-button';
@use '@material/button';
.foo-button {
@include button.container-fill-color(darksalmon);
}
We also need to configure sass-loader to understand the @material imports used by MDC Web. Update your webpack.config.js by changing { loader: 'sass-loader' } to:
xxxxxxxxxx
{
loader: 'sass-loader',
options: {
// Prefer Dart Sass
implementation: require('sass'),
// See https://github.com/webpack-contrib/sass-loader/issues/804
webpackImporter: false,
sassOptions: {
includePaths: ['./node_modules']
},
}
}
Note: Configuring includePaths should suffice for most cases where all MDC Web packages are kept up-to-date together. If you encounter problems compiling Sass due to nested node_modules directories, see the
Appendix below on how to configure a custom importer instead.
In order to add vendor-specific styles to the Sass files, we need to configure autoprefixer through PostCSS.
You'll need all of these Node dependencies:
autoprefixer : Parses CSS and adds vendor prefixes to CSS rulespostcss-loader : Loader for Webpack used in conjunction with autoprefixer
You can install all of them by running this command:
xxxxxxxxxx
npm install --save-dev autoprefixer postcss-loader
Add autoprefixer at the top of your webpack.config.js:
xxxxxxxxxx
const autoprefixer = require('autoprefixer');
Then add postcss-loader, using autoprefixer as a plugin:
xxxxxxxxxx
{ loader: 'extract-loader' },
{ loader: 'css-loader' },
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
autoprefixer()
]
}
}
},
{
loader: 'sass-loader',
options: {
sassOptions: {
includePaths: ['./node_modules']
},
// Prefer Dart Sass
implementation: require('sass'),
// See https://github.com/webpack-contrib/sass-loader/issues/804
webpackImporter: false,
}
},
@material/button has
xxxxxxxxxx
<body>
<button class="foo-button mdc-button">
<div class="mdc-button__ripple"></div>
<span class="mdc-button__label">Button</span>
</button>
</body>
Now run npm start again and open
Step 3: Webpack with ES2015
We need to configure webpack to bundle ES2015 JavaScript into standard JavaScript, through
@babel/core babel-loader : Compiles JavaScript files using babel@babel/preset-env : Preset for compiling es2015
You can install all of them by running this command:
xxxxxxxxxx
npm install --save-dev @babel/core babel-loader @babel/preset-env
In order to demonstrate how webpack bundles our JavaScript, you’ll need to update index.html to include JavaScript. The JavaScript file is generated by babel-loader, which compiles ES2015 files into JavaScript. Add this script tag to index.html before the closing </body> tag:
xxxxxxxxxx
<script src="bundle.js" async></script>
And create a simple ES2015 file called app.js:
xxxxxxxxxx
console.log('hello world');
Then configure webpack to convert app.js into bundle.js by modifying the following properties in the webpack.config.js file:
- Change entry to an array containing both app.scss and app.js:
xxxxxxxxxx
entry: ['./app.scss', './app.js']
- Change output.filename to be bundle.js:
xxxxxxxxxx
output: {
filename: 'bundle.js',
}
- Add the babel-loader object to the rules array after the sass-loader object:
xxxxxxxxxx
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: ['@babel/preset-env'],
},
}
The final webpack.config.js file should look like this:
xxxxxxxxxx
const autoprefixer = require('autoprefixer');
module.exports = {
entry: ['./app.scss', './app.js'],
output: {
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.scss$/,
use: [
{
loader: 'file-loader',
options: {
name: 'bundle.css',
},
},
{loader: 'extract-loader'},
{loader: 'css-loader'},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
autoprefixer()
]
}
}
},
{
loader: 'sass-loader',
options: {
// Prefer Dart Sass
implementation: require('sass'),
// See https://github.com/webpack-contrib/sass-loader/issues/804
webpackImporter: false,
sassOptions: {
includePaths: ['./node_modules'],
},
},
}
],
},
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: ['@babel/preset-env'],
},
}
],
},
};
Now run npm start again and open
Step 4: Include JavaScript for a component
Now that you have webpack configured to compile ES2015 into JavaScript, let's include the ES2015 files from the Material Design ripple. First, install the Node dependency:
xxxxxxxxxx
npm install @material/ripple
We need to tell our app.js to import the ES2015 file for @material/ripple. We also need to initialize an MDCRipple with a DOM element. Replace your “hello world” version of app.js with this code:
xxxxxxxxxx
import {MDCRipple} from '@material/ripple/index';
const ripple = new MDCRipple(document.querySelector('.foo-button'));
Note: We explicitly reference index within each MDC Web package in order to import the ES2015 source directly. This allows for tree-shaking and avoiding duplicate code for common dependencies (e.g. Ripple). However, it requires transpiling the MDC Web modules using the tools installed in Step 3.
Now run npm start again and open
Step 5: Build Assets for Production
Up to this point, we've used webpack-dev-server to preview our work with live updates. However, webpack-dev-server is not intended for production use. Instead, we should generate production-ready assets.
Add another script to package.json:
xxxxxxxxxx
"scripts": {
"build": "webpack",
"start": "webpack serve"
}
Now run the following command:
xxxxxxxxxx
npm run build
This will produce bundle.js and bundle.css in the project directory. These contain the compiled CSS and transpiled JS, which you can then copy into a directory served by any web server.
Appendix: Configuring a Sass Importer for Nested node_modules
It is possible to end up with nested node_modules folders if you have dependencies on conflicting versions of individual MDC Web packages. This may lead to errors when attempting to compile Sass with the includePaths configuration shown above, since Sass is only scanning for @material packages under the top-level node_modules directory.
Alternatively, you can implement an importer as follows, which makes use of node's module resolution algorithm to find the dependency nearest to the file that imported it. Add the following code near the top of your webpack.config.js (before the exports):
xxxxxxxxxx
const path = require('path');
function tryResolve_(url, sourceFilename) {
// Put require.resolve in a try/catch to avoid node-sass failing with cryptic libsass errors
// when the importer throws
try {
return require.resolve(url, {paths: [path.dirname(sourceFilename)]});
} catch (e) {
return '';
}
}
function tryResolveScss(url, sourceFilename) {
// Support omission of .scss and leading _
const normalizedUrl = url.endsWith('.scss') ? url : `${url}.scss`;
return tryResolve_(normalizedUrl, sourceFilename) ||
tryResolve_(path.join(path.dirname(normalizedUrl), `_${path.basename(normalizedUrl)}`),
sourceFilename);
}
function materialImporter(url, prev) {
if (url.startsWith('@material')) {
const resolved = tryResolveScss(url, prev);
return {file: resolved || url};
}
return {file: url};
}
Then update your sass-loader config to the following:
xxxxxxxxxx
{
loader: 'sass-loader',
options: {
// Prefer Dart Sass
implementation: require('sass'),
// See https://github.com/webpack-contrib/sass-loader/issues/804
webpackImporter: false,
sassOptions: {
importer: materialImporter,
includePaths: ['./node_modules'],
},
},
}