- npm: react-material-web
- Source: anthonyleung-dev/react-material-web
- Changelog: CHANGELOG.md
This library provides a set of React components styled with Material Design, leveraging the capabilities of @material/web and @lit/react.
To install Material Web React, you can use npm or yarn. Run one of the following commands in your project directory:
npm install react-material-webor
yarn add react-material-webHere's a quick example to get you started. After installing, you can import and use Material Components like any other React component.
We default to using the @fontsource/roboto and material-symbols in styles, if you want to use them, you can import them in your project:
Add styles to your project:
import 'react-material-web/styles'Or you can use the components without default styles.
Then, you can use the components like this:
import React from 'react';
import { MdFilledButton } from 'react-material-web';
function Example() {
return (
<div>
<MdFilledButton>Click me</MdFilledButton>
</div>
);
}For more detailed documentation on each component and its API, please refer to Material Components Web.
You can also check out our Storybook to see all the components in action. To run the Storybook, use the following command:
npm run storybookor
- ✅ Button
- ✅ FAB
- ✅ Icon
- ✅ Icon button
- ✅ Checkbox
- ✅ Chips
- ✅ Dialog
- ✅ Divider
- ✅ Elevation
- ✅ Focus ring
- ✅ List
- ✅ Menu
- ✅ Progress indicators
- ✅ Radio
- ✅ Ripple
- ✅ Select
- ✅ Slider
- ✅ Switch
- ✅ Tabs
- ✅ Text field
WARNING
⚠️ This folder contains experimental features that are not recommended for production.
- ✅ Badge
- ✅ Card
- ✅ Segmented button
- ✅ Navigation bar
Only using the components above? Skip this section. The package root needs no new setup.
WARNING
⚠️ These components come from@material/web/labs/gb, added in@material/web2.5. They are experimental. Their API can change in a minor release.
They have their own entry point. The expressive Badge and Card differ from the Labs Badge and Card above.
import { MdGbButton, MdGbIcon } from 'react-material-web/labs/gb'- ✅ Badge (
MdGbBadge) - ✅ Button (
MdGbButton) - ✅ Card (
MdGbCard) - ✅ Checkbox (
MdGbCheckbox) - ✅ Divider (
MdGbDivider) - ✅ FAB (
MdGbFab) - ✅ Icon (
MdGbIcon) - ✅ Icon button (
MdGbIconButton) - ✅ List (
MdGbList,MdGbListItem) - ✅ Menu (
MdGbMenu,MdGbMenuGroup,MdGbMenuItem) - ✅ Radio (
MdGbRadio) - ✅ Split button (
MdGbSplitButton) - ✅ Switch (
MdGbSwitch)
-
Load the M3 system stylesheet once. The expressive components read their color, shape, type and motion tokens from it.
import '@material/web/labs/gb/styles/m3.css'
It uses
light-dark()colors, so it follows the user's color scheme. With pnpm, add@material/webas a direct dependency so this import resolves. -
Add the bundler rule. Upstream loads its styles as CSS module scripts. Most bundlers cannot load them. The rule rewrites each style import to the
.cssresult.jsfile next to it. Get the rule fromreact-material-web/labs/gb/bundler. This entry is for bundler config files only. Do not import it in app code.Vite 8
// vite.config.js import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import { materialGbVite } from 'react-material-web/labs/gb/bundler' export default defineConfig({ plugins: [materialGbVite(), react()], // The dev dependency optimizer has its own plugin list. optimizeDeps: { rolldownOptions: { plugins: [materialGbVite()] } }, // Only for SSR builds and Vitest: bundle these packages so the plugin runs on them. ssr: { noExternal: ['react-material-web', '@material/web'] }, })
On Vite 7, replace the
optimizeDepsline withoptimizeDeps: { exclude: ['react-material-web', '@material/web'] }. Vite 7 pre-bundles with esbuild, which does not run this plugin.webpack 5
// webpack.config.js const { materialGbWebpackRule } = require('react-material-web/labs/gb/bundler') module.exports = { // ... module: { rules: [ // ...your rules materialGbWebpackRule(), ], }, }
Next.js 15.5 and 16
Next.js 16 uses Turbopack by default; the
webpackkey coversnext build --webpack. Next.js 15.5 uses webpack by default; theturbopackkey covers--turbopack. Next.js 15.2 and older ignore theturbopackkey, so Turbopack builds fail there.// next.config.mjs import { materialGbTurbopackRules, materialGbWebpackRule } from 'react-material-web/labs/gb/bundler' export default { turbopack: { rules: materialGbTurbopackRules() }, webpack: (config) => { config.module.rules.push(materialGbWebpackRule()) return config }, }
Without the rule, you see one of these errors:
Bundler Symptom Vite does not provide an export named 'default'for a.cssfile in dev, or"default" is not exported by ...cssat build timeVitest Unknown file extension ".css"webpack, with a CSS loader rule The build passes. The components render empty. The browser console shows Cannot read properties of undefined (reading 'styleSheet')webpack, without a CSS loader rule Module parse failed: Unexpected character '@'in a gb.cssfileNext.js (Turbopack) non-ecmascript placeable asset ... has no ECMAScript exports -
Load an icon font for
MdGbIcon. It uses the font named by the--md-icon-fontcustom property. This library already depends onmaterial-symbols:import 'material-symbols/outlined.css'
:root { --md-icon-font: 'Material Symbols Outlined'; }
import 'react-material-web/styles'loads allmaterial-symbolsfonts too.
A first component after these steps:
import '@material/web/labs/gb/styles/m3.css'
import 'material-symbols/outlined.css'
import { MdGbButton, MdGbIcon } from 'react-material-web/labs/gb'
export function Save() {
return (
<MdGbButton color="filled" size="md">
<MdGbIcon>save</MdGbIcon>
Save
</MdGbButton>
)
}The menu is a native popover. Open it from a button that points at the menu id. On React 19, use the popoverTarget prop:
<>
<button popoverTarget="menu">Open</button>
<MdGbMenu id="menu">
<MdGbMenuItem>Item</MdGbMenuItem>
</MdGbMenu>
</>React 18 has no popoverTarget prop. Pass the HTML attribute instead: <button {...{ popovertarget: 'menu' }}>Open</button>.
In jsdom (for example Vitest), form-associated components need an ElementInternals polyfill such as element-internals-polyfill. This applies to the stable components too.
Tested with Vite 7 and 8, Vitest 5 with jsdom, webpack 5, Next.js 15.5 and 16, and React 18 and 19.
Our library is built upon the solid foundation of Material Design and modern web technologies, including:
- @material/web: For Material Design components.
- @lit/react: For creating Lit-based components within React.
- @fontsource/roboto: The default Material Design font.
- material-symbols: For Material Design icons and symbols.
GitHub Actions publishes to npm. Each release has npm provenance.
-
Set
versioninpackage.jsonand add the entry toCHANGELOG.md. Merge tomain. -
Tag that commit with the same version, without a
v, and push the tag:git tag 2.5.0 git push origin 2.5.0
-
The
Publishworkflow runs the tests and the builds, checks that the tag equals thepackage.jsonversion, and publishes. A prerelease version such as2.6.0-beta.1goes to thenextdist-tag.
The workflow uses npm trusted publishing (OIDC), so the repo stores no npm token.
Distributed under the MIT License. See LICENSE for more information.