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

react-material-expressive

v1.1.2

Published

Material 3 Expressive React component library. Framework-agnostic, precompiled CSS, official M3 design tokens.

Downloads

684

Readme

react-material-expressive

npm version CI license: MIT

React component system implementing Material 3 Expressive: official M3 design tokens, state layers, the full type/shape/elevation scales and motion — framework-agnostic (no next/*), RSC/SSR friendly, with precompiled CSS (you don't set up Tailwind) and runtime theming via CSS variables.

🤖 LLM- and agent-friendly. Start from the machine-readable index llms.txt — every component linked with a one-line description. It's also resolvable as react-material-expressive/llms.txt and pointed to by the llmsTxt field in package.json.

  • React >= 19 (peer dependency). ESM + CJS + TypeScript types.
  • Pure UI kit: presentational, controllable components. No business logic, no data fetching, no app state.
  • Machine-readable docs per component in docs/components/.
  • Live demo: react-material-expressive.vercel.app (the Storybook, redeployed on every push).

Installation

npm install react-material-expressive react react-dom

React 19+ is a peer dependency. The package ships precompiled CSS, ESM + CJS builds and TypeScript types — there is nothing else to configure.

Quickstart

// 1. Import the precompiled stylesheet ONCE (global CSS / root layout).
import "react-material-expressive/styles.css";

// 2. Use the components.
import {Button, Card, Dialog, Switch} from "react-material-expressive";

export function Example() {
  return (
    <Card variant="elevated">
      <Card.Body>
        <Switch defaultChecked label="Notifications" />
      </Card.Body>
      <Card.Footer className="justify-end">
        <Button variant="text">Dismiss</Button>
        <Button>Accept</Button>
      </Card.Footer>
    </Card>
  );
}

No Tailwind, no ThemeProvider, no configuration. Components are client components ("use client" is embedded in every entry), so they can be imported directly from React Server Components.

Exports

The package has a single JavaScript entry, the precompiled stylesheet and an optional Tailwind partial:

| Import | Contents | | ------------------------------------------- | ---------------------------------------------------- | | react-material-expressive | all components, elements and layers | | react-material-expressive/styles.css | precompiled stylesheet (import once) | | react-material-expressive/theme.css | raw Tailwind v4 partial — only to extend (see below) |

Theming

Everything resolves through official M3 tokens at runtime: --md-sys-color-* (full 49-role scheme), --md-sys-shape-corner-*, --md-sys-elevation-level1..5, --md-ref-typeface-brand/plain.

  • :root ships the light scheme and .dark, [data-theme="dark"] the dark one — both verbatim Material Theme Builder exports.

Theme switching uses the prebuilt ToggleTheme / ToggleThemeMenu components (there is no ThemeProvider): they read/write data-theme on <html> (SSR-safe, synced across instances and tabs) and persist to localStorage.

import {ToggleTheme} from "react-material-expressive";

<ToggleTheme />;

There is no public JavaScript theming API — customization is done purely through CSS token overrides (see below).

Custom themes (cascade override)

The CSS is precompiled and only reads variables, so a custom theme is just a token override. Paste a Material Theme Builder export verbatim:

/* my-brand.css — loaded after styles.css */
:root {
  --md-sys-color-primary: #006a60;
  --md-sys-color-on-primary: #ffffff;
  /* ...rest of the export... */
}

Scoped themes work the same way on any element: any class or data-theme scope that overrides the tokens re-themes its subtree.

Typography

The type scale ships as utilities (text-display-largetext-label-small) that inherit two typeface tokens. Fonts are named but never bundled — load yours and point the tokens at it:

:root {
  --md-ref-typeface-brand: "Google Sans", system-ui, sans-serif;
  --md-ref-typeface-plain: "Google Sans Text", system-ui, sans-serif;
}

Extending with your own Tailwind (optional)

Most apps only import styles.css. If you run your own Tailwind v4 and want to write markup with the same M3 utilities the library uses — bg-primary, text-on-surface, rounded-extra-large, shadow-mm-1, text-headline-small, even token roles the precompiled CSS never emitted — import the raw partial into your Tailwind entry:

@import "tailwindcss";
@import "react-material-expressive/theme.css";

That's all you need: the mappings are @theme inline, so the utilities re-resolve per element and switch light/dark automatically by following the tokens (their values come from the styles.css you already import for the components — or a Material Theme Builder paste). theme.css also registers the dark: variant against the library's .dark/[data-theme] toggle, so explicit dark: utilities in your code match the components.

Icons

Components take icons as ReactNode (icon, iconLeft, iconRight, leftElement…) — the library bundles no icon font or icon package. Recommended: Material Symbols (variable font). Load it yourself, e.g.:

<link
  href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,[email protected],100..700,0..1,-50..200&display=block"
  rel="stylesheet" />

and use the zero-dependency helper:

import {MaterialSymbol} from "react-material-expressive";

<Button iconLeft={<MaterialSymbol name="add" size={18} />}>New</Button>;

Images and links (framework-agnostic)

There are no proprietary Image/Link components. Image-like components (Avatar, Img, Stories.User…) accept src: string | StaticImageData and render a native <img> (object-fit + hide-on-error), or let you inject your framework's component with priority render > image > children:

import Image from "next/image"; // in YOUR app, not in the library

<Avatar
  src={photo}
  render={({src, alt, className, style}) => (
    <Image alt={alt} className={className} fill src={src!} style={style} />
  )}
/>;

Navigation components render native <a href> and derive their active state from active or currentPath (resolveActive); client-side routing plugs in via onClick or a wrapper.

State layers, disabled, motion

  • Interaction states follow M3 state layers (hover 8%, focus 10%, pressed 10%) — exposed as the .state-layer class for custom items.
  • Disabled follows M3: container 12% / content 38% of on-surface.
  • Entrances use emphasized-decelerate (400ms), exits emphasized-accelerate (200ms); overlays stay mounted during their exit animation.

Internationalization (i18n)

Every component with user-facing text accepts a labels prop — an object of optional strings (a few are ReactNode) merged over the built-in English defaults. Override one instance, or pass the same object everywhere to localize the whole app. The library ships English defaults only; the translations are yours to provide (like the fonts and icons, named but not bundled).

<Snackbar text="Foto archivada" labels={{dismiss: "Descartar"}} showClose />
<Chips onRemove={remove} labels={{remove: "Quitar"}}>Etiqueta</Chips>
<SearchInput labels={{placeholder: "Buscar"}} />

labels covers chrome and accessible names only. Date/number formatting is driven by a separate locale prop on the pickers (native Intl), and the date/time pickers expose their full label sets too (DatePickerLabels, TimePickerLabels, …). Each component's *Labels type is exported from the barrel.

Consolidating every string under labels renamed a few single-purpose text props (breaking):

| Component | Old prop | New | | ------------------------------------ | ------------- | ------------------------ | | FABMenu | label | labels={{open}} | | SplitButton | menuLabel | labels={{menu}} | | SearchInput | placeholder | labels={{placeholder}} | | Slider / SliderDual | aria-label | labels={{label}} | | Progress / Circle / LoadingIndicator | aria-label | labels={{label}} | | Amount | aria-label | labels={{label}} | | Loading | label | labels={{label}} |

The theme-name strings of ToggleThemeMenu stay in its themes list (an {id, label} array), not in labels.

Component catalog

| Family | Docs | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Buttons | Button · ButtonGroup · ButtonGroupConnected · IconButton · FAB / ExtendedFAB · FABMenu · SplitButton | | Communication | Badge · Progress / Circle · LoadingIndicator · Snackbar · Tooltip · Loading | | Containment | Card · Dialog · Sheets · Divider · List · Table | | Selection & input | Checkbox · Radio · Switch · Chips · Slider / SliderDual · TextField · Select · Combobox · Amount · DatePicker · TimePicker | | Navigation | NavigationBar · NavigationRail · TopAppBar · Toolbars · Tabs · Link · Search | | Menus | Menu · Dropdown · OverflowMenu · ToggleTheme | | Media & showcase | Avatar · AvatarStack · Img · MediaFrame · Gallery · Stories · Video · Perspective · Blob | | Text & icons | TextElement · Icon · MaterialSymbol | | Layout | Layers |

Expressive-only

This kit is Material 3 Expressive only. Components and variants that the M3 Expressive spec marks "no longer recommended" are not shipped: the NavigationDrawer (→ expanded NavigationRail), BottomAppBar (→ DockedToolbar) and SegmentedButtons (→ ButtonGroupConnected with toggles) components were removed, as were the FAB surface color / small (40dp) size, the Slider classic prop, the TopAppBar Medium/Large baseline prop and the NavigationBar tall height. The expressive default is the only path.

Where the spec keeps more than one valid style, the recommended one is the default and the alternative stays available:

| Component | Default (recommended) | Still-available alternative | | ------------------------------------------------ | ------------------------------ | --------------------------- | | List | variant="expressive" (tiles) | variant="plain" | | Search | contained (gapped card) | divided prop | | Progress / Circle | flat indicator | wavy prop |

Versioning

This project follows Semantic Versioning: breaking changes bump the major version, new features the minor, and fixes the patch. See the CHANGELOG for every release, with a migration note on each breaking change so you know exactly what to adjust when upgrading.

Development (this repo)

npm install
npm run build            # dist/: css + esm + cjs + dts + themes
npm run typecheck && npm run lint && npm test

See AGENTS.md for architecture and conventions, and CONTRIBUTING.md for how to contribute. The interactive component workbench (Storybook) lives in a separate repository.

License

MIT