From npm install to a rendered, on-spec Button — this page gets you there in about five
minutes, nothing skipped.
npm install @brijbyte/md3-react @base-ui/react
# or
pnpm add @brijbyte/md3-react @base-ui/react
Most components wrap a headless Base UI primitive, so you get correct behavior, accessibility, and keyboard handling for free — the library's job is just making it look exactly like the Material Design 3 spec, not reinventing how it works.
JavaScript and CSS are decoupled — importing a component does not pull in its styles, so
your CSS payload only ever grows with what you actually use, never the whole library. Add
these imports to your entry-point css file (e.g. index.css):
/* required: tokens + theming */
@import "@brijbyte/md3-react/tokens.css";
/* required by most pressable components */
@import "@brijbyte/md3-react/ripple.css";
and then import the component css you need wherever required:
@import "@brijbyte/md3-react/button.css";
Every typescale role resolves to --md-ref-typeface-brand (display/headline/title-large)
or --md-ref-typeface-plain (body/label/title-medium/title-small), both of which default
to "Roboto", system-ui, sans-serif in tokens.css. The typescale only ever uses weights
400 and 500, so that's all you need to load:
<link
href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap"
rel="stylesheet"
/>
Or self-host via Fontsource instead of Google's CDN:
npm install @fontsource/roboto
import "@fontsource/roboto/400.css";
import "@fontsource/roboto/500.css";
To use a different typeface (or Google's variable Roboto Flex), override the two ref
tokens after importing tokens.css — both roles can point at the same font, or you can
split brand vs. plain to mix a display face with a text face:
@import "@brijbyte/md3-react/tokens.css";
:root {
--md-ref-typeface-brand: "Google Sans", system-ui, sans-serif;
--md-ref-typeface-plain: "Roboto", system-ui, sans-serif;
}
Import each component (and its css) from its own path:
import { Button } from "@brijbyte/md3-react/button";
import AddIcon from "@brijbyte/md3-icons/outlined/Add";
import "@brijbyte/md3-react/button.css";
<Button variant="tonal" icon={<AddIcon />}>
Add item
</Button>;
Nothing is hidden behind the wrapper: every Base UI prop — render, disabled, event
handlers — passes straight through and works exactly as its own docs describe:
Dark mode isn't an afterthought bolted onto light-mode colors — every color is a CSS custom
property (--md-sys-color-*) with its own dark value baked in. It kicks in automatically via
prefers-color-scheme, or force it with a data-theme attribute on <html>:
<html data-theme="dark"></html>
No specificity fights: the library's CSS lives in the theme / components cascade
layers (Tailwind v4's own layer names), so any unlayered Tailwind utility you write beats
it automatically — no !important, no .root.root hacks. See
Tailwind overrides for the full setup, including using MD3 tokens as
Tailwind utilities (bg-primary, text-title-large, shadow-level1, …).