npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

m3-expressive-react

v1.3.1

Published

Material Design 3 (Expressive) component library for React — token-first, spec-driven, MUI-idiomatic API

Readme

m3-expressive-react

Material Design 3 (Expressive) component library for React.

Token-first and spec-driven: every component reads from MD3 design tokens (--md-sys-* CSS custom properties), color is generated at runtime from a seed via Dynamic Color, and behavior is built on native elements with hand-rolled, APG-compliant interaction patterns — no external a11y framework.

The public API is deliberately MUI-idiomatic (one component per MD3 component selected by variant, onChange(event, value), startIcon/endIcon, controlled/uncontrolled pairs), while appearance, defaults, and behavior follow the MD3 spec and Jetpack Compose material3.

Documentation: minop1205.github.io/m3-expressive-react — guides, live demos, and generated prop tables.

Install

npm install m3-expressive-react

Requires React 18 or 19.

Quick start

import { ThemeProvider, Button } from 'm3-expressive-react'
import 'm3-expressive-react/styles.css'

export function App() {
  return (
    <ThemeProvider seedColor="#6750A4" mode="light">
      <Button variant="filled" onClick={() => console.log('clicked')}>
        Hello MD3
      </Button>
    </ThemeProvider>
  )
}

The styles.css import is required — it carries the design tokens (shape, motion, state, typescale) every component references. Components intentionally ship without per-value fallbacks; colors come from ThemeProvider, which generates the full MD3 color-role map (light/dark) from your seed color.

CSS minifiers: the styles use modern CSS such as @starting-style (popup entry transitions). cssnano and Lightning CSS handle it; clean-css does not — it drops the rules inside @starting-style and corrupts the rules that follow. If your build minifies CSS with clean-css (e.g. Docusaurus' default minimizer — set USE_SIMPLE_CSS_MINIFIER=true), switch to cssnano or Lightning CSS.

Per-component imports

Every component folder is also its own entry point with a default export, so you can import MUI-style and load only the CSS you use:

import 'm3-expressive-react/tokens.css' // once, at the app root
import { ThemeProvider } from 'm3-expressive-react'
import Button from 'm3-expressive-react/Button'
import Radio, { RadioGroup } from 'm3-expressive-react/Radio'
import type { ButtonProps } from 'm3-expressive-react/Button'
  • Default export = the component the folder is named after (Button, Radio, Chip, Card, Menu, Snackbar, …). Two folders have no namesake: AppBar → TopAppBar, ProgressIndicator → LinearProgressIndicator. Every named export and type of the folder (RadioGroup, ChipSet, MenuItem, SnackbarProvider, BottomAppBar, CircularProgressIndicator, …) is available from the same subpath.
  • CSS loads automatically: a subpath module imports its own CSS (plus the shared Ripple / FocusRing styles), so your bundler — Vite, webpack 5 with css-loader, Next.js app and pages router — ships only the styles of the components you import. The design tokens stay global: import tokens.css once instead of styles.css.
  • Root and subpath imports can be mixed — they share the same modules (one RadioGroup context, one ThemeProvider). The root entry is unchanged and still tree-shaken.

| You import components from… | Import this CSS once | | ------------------------------------- | ----------------------------------------------------- | | m3-expressive-react (root) | m3-expressive-react/styles.css (every component) | | m3-expressive-react/<Component> | m3-expressive-react/tokens.css (tokens + typescale) |

Notes:

  • Don't combine styles.css with subpath imports: the subpath CSS would be loaded a second time (bigger CSS, and the repeated rules can reorder the cascade). Pick one setup.
  • Environments without CSS imports get CSS-free modules: require() (CJS, Jest) and server-side Node import (the node export condition — e.g. SSR with externalized dependencies) never touch a .css file; the client bundle carries the styles. If your bundler cannot import CSS at all, use the root entry with styles.css.
  • Types resolve with TypeScript moduleResolution bundler, node16, nodenext and legacy node.

Components

Buttons & actions — Button, IconButton, ButtonGroup, SplitButton, SegmentedButton, Fab, FabMenu, Chip / ChipSet

Selection & input — Checkbox, Radio / RadioGroup, Switch, Slider, TextField, SearchBar, DatePicker, TimePicker

Navigation — AppBar, Toolbar, NavigationBar, NavigationRail, NavigationDrawer, Tabs, Menu

Containment & communication — Card, List, Carousel, Dialog, BottomSheet, SideSheet, Snackbar, Tooltip, Badge, Divider, ProgressIndicator, LoadingIndicator, SwipeToDismiss

See the components page of the docs site for live demos and prop tables.

Theming

Reference tokens  →  System tokens (--md-sys-*)  →  Component tokens (--_*)
  • Static foundations (type scale, shape, elevation, motion, state-layer opacities) ship in styles.css as CSS custom properties.
  • Color is dynamic: ThemeProvider uses @material/material-color-utilities to derive every --md-sys-color-* role from seedColor, for mode="light" | "dark".
  • Focus rings and ripples expose small --md-focus-ring-* / --md-ripple-* contract variables for tuning.

More in the theming guide.

Icons

The library ships no icons: every icon prop (icon, startIcon, selectedIcon, …) takes a ReactNode, sized and colored by the component. We recommend Material Symbols as SVG components (@material-symbols/svg-400 + SVGR):

import Search from '@material-symbols/svg-400/outlined/search.svg?react'

<IconButton icon={<Search />} aria-label="Search" />

This needs a bundler plugin and a TypeScript declaration. See the Icons guide for step-by-step Vite and Next.js setup, plus notes on icon fonts and other icon libraries.

Spec fidelity

Components are implemented against m3.material.io (design source of truth) and Jetpack Compose androidx.compose.material3 (behavior, defaults, motion — exact values read from the AndroidX sources), with adjudicated spec sheets and audit reports in docs/. Interaction states use the current MD3 values (hover 0.08 / focus 0.10 / pressed 0.10 state layers), and motion approximates Compose's spring specs.

Migrating from 0.x

See the migration guide (docs/migration-v1.md) for the complete v1 breaking-change guide with before/after tables and a checklist.

Development

npm install
npm run dev      # Storybook
npm test         # Vitest (+ Testing Library + axe)
npm run build    # library build (dist/)
npm run vrt      # visual regression (see CLAUDE.md for baseline rules)

The docs site lives in site/ (Docusaurus) and deploys to GitHub Pages from develop:

cd site && npm install && npm start

See CONTRIBUTING.md for guidelines. This project uses Conventional Commits.

Tech stack

| Concern | Choice | | ------- | ------ | | Build | Vite (library mode) + TypeScript | | Styling | CSS Modules + CSS custom properties (design tokens) | | A11y | Native elements + hand-rolled APG patterns; axe-tested | | Color | @material/material-color-utilities (Dynamic Color) | | Docs/dev| Storybook; Docusaurus docs site | | Tests | Vitest + Testing Library + axe; Playwright visual regression |

License

MIT