Revisiting Material Design For The Web
Material Design 3 is a very good design library coming from Google and it's the latest version of their Material Design design language.
There are versions of Material for all the languages and libraries Google makes available:
This post will concentrate on Material Design Web and try to do the following:
- Explain what is Material Design
- Explain how to build a design/layout with Material Design Web
- Decide if the library is still worth using since it went into maintenance mode due to Google reassigning the engineering team working on Material Web to work on implementing Material for Wiz (before the merge with Angular)
Getting Started #
The Material Design Web Quick Start provides a good way to look at Material Design for evaluation.
The Kitchen Sink Approach #
The easiest way to build material design is to use the all.js
import, what I call the kitchen sink. The all.js
import will import all available Material Design components, making them available for you to play with.
The first step is to load Roboto from Google Fonts
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
<script type="importmap">
{
"imports": {
"@material/web/": "https://esm.run/@material/web/"
}
}
</script>
<script type="module">
import '@material/web/all.js';
import {styles as typescaleStyles} from '@material/web/typography/md-typescale-styles.js';
document.adoptedStyleSheets.push(typescaleStyles.styleSheet);
</script>
<h1 class="md-typescale-display-medium">Hello Material!</h1>
<form>
<p class="md-typescale-body-medium">Check out these controls in a form!</p>
<md-checkbox></md-checkbox>
<div>
<md-radio name="group"></md-radio>
<md-radio name="group"></md-radio>
<md-radio name="group"></md-radio>
</div>
<md-outlined-text-field label="Favorite color" value="Purple"></md-outlined-text-field>
<md-outlined-button type="reset">Reset</md-outlined-button>
</form>
<style>
form {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 16px;
}
</style>
Note that this is not meant for production since it will invariably load code that your project won't use. For production code, you should import individual components and use a build system to bundle them together for wide browser support.
Individual Components #
import '@material/web/button/filled-button.js';
import '@material/web/button/outlined-button.js';
import '@material/web/checkbox/checkbox.js';
import '@material/web/list/list.js';
import '@material/web/list/list-item.js';
import {styles as typescaleStyles} from '@material/web/typography/md-typescale-styles.js';
document.adoptedStyleSheets.push(typescaleStyles.styleSheet);
Use the <component-name> tag in HTML markup. Refer to the [component docs] for more guidance on using each component.
<script type="module" src="./index.js"></script>
<h1 class="md-typescale-display-medium">Hello Material!</h1>
<label>
Material 3
<md-checkbox checked></md-checkbox>
</label>
<div>
<md-outlined-button>Back</md-outlined-button>
<md-filled-button>Next</md-filled-button>
</div>
<div>
<md-list style="max-width: 300px;">
<md-list-item>
Fruits
</md-list-item>
<md-divider></md-divider>
<md-list-item>
Apple
</md-list-item>
<md-list-item>
Banana
</md-list-item>
<md-list-item>
<div slot="headline">Cucumber</div>
<div slot="supporting-text">Cucumbers are long green fruits that are just as long as this multi-line description</div>
</md-list-item>
<md-list-item
type="link"
href="https://google.com/search?q=buy+kiwis&tbm=shop"
target="_blank">
<div slot="headline">Shop for Kiwis</div>
<div slot="supporting-text">This will link you out in a new tab</div>
<md-icon slot="end">open_in_new</md-icon>
</md-list-item>
</md-list>
</div>
Quick Build #
npm install rollup @rollup/plugin-node-resolve
Create a bundle from an entry point index.js file:
npx rollup -p @rollup/plugin-node-resolve index.js -o bundle.js
Use the generated bundle in a <script> "src" attribute:
<script src="./bundle.js"></script>
The Build Process #
https://lit.dev/docs/tools/production/
npm i --save-dev rollup \
@web/rollup-plugin-html \
@web/rollup-plugin-copy \
@rollup/plugin-node-resolve \
@rollup/plugin-terser \
rollup-plugin-summary
// Import rollup plugins
import { rollupPluginHTML as html } from '@web/rollup-plugin-html';
import {copy} from '@web/rollup-plugin-copy';
import resolve from '@rollup/plugin-node-resolve';
import terser from '@rollup/plugin-terser';
import summary from 'rollup-plugin-summary';
export default {
plugins: [
// Entry point for application build; can specify a glob to build multiple
// HTML files for non-SPA app
html({
input: 'index.html',
}),
// Resolve bare module specifiers to relative paths
resolve(),
// Minify JS
terser({
ecma: 2021,
module: true,
warnings: true,
}),
// Print bundle summary
summary(),
// Optional: copy any static assets to build directory
// copy({
// patterns: ['images/**/*'],
// }),
],
output: {
dir: 'build',
},
preserveEntrySignatures: 'strict',
};
Serving the content #
Install Web Dev Server:
npm i --save-dev @web/dev-server
Then add the following to the "scripts" section in package.json:
"start": "web-dev-server build/index.html--open --watch"
Start the server:
web-dev-server --node-resolve --open
wds --node-resolve --open
Run in watch mode, reloading on file changes:
web-dev-server --node-resolve --watch --open
Transform JS to a compatible syntax based on the user agent:
web-dev-server --node-resolve --open --esbuild-target auto
Building a Layout #
Should we use it? #
https://github.com/material-components/material-web/tree/main/docs/components