MD3 React

Typography

One component, fifteen type roles — change the tag, keep the scale.
import { Typography } from "@brijbyte/md3-react/typography";
@import "@brijbyte/md3-react/typography.css";

Type scale

Stop guessing font sizes. MD3 defines five roles — display, headline, title, body, and label — in three sizes each, and variant picks the role directly (default body-large). Every value maps 1 to the --md-sys-typescale-* tokens, so retheming the tokens restyles every Typography in the app at once.

display-large

Display large

display-medium

Display medium

display-small

Display small

headline-large

Headline large

headline-medium

Headline medium

headline-small

Headline small

title-large
Title large
title-medium
Title medium
title-small
Title small
body-large

Body large

body-medium

Body medium

body-small

Body small

label-largeLabel large
label-mediumLabel medium
label-smallLabel small

Changing fonts

Swap your brand typeface once and it propagates everywhere — no hunting down every heading in the app. Each variant reads its typeface from its own --md-sys-typescale-<variant>-font variable, so a plain CSS override retargets one role, or every role at once via the two ref typefaces they default to: --md-ref-typeface-brand (display, headline, and title-large) and --md-ref-typeface-plain (everything else).

:root {
  /* All brand-typeface variants at once… */
  --md-ref-typeface-brand: "Google Sans", sans-serif;
  /* …or just one variant. */
  --md-sys-typescale-display-large-font: "Playfair Display", serif;
}

The same pattern works for the other per-variant tokens: -size, -line-height, -weight, and -tracking. This site does exactly that: the brand typeface is Google Sans (the headings above, and the nav), while plain is Roboto for body text.

Semantics

Style and markup are two different decisions, and Typography never confuses them: variant picks the visual style, and it defaults to sensible HTML for that style, so a plain <Typography variant="headline-large"> already renders h1title-* renders h3h6, body-* renders p, and label-* renders span. Need a display-large look on an h2 for SEO, or any other mismatch? Pass as and only the markup changes.

Blog post title

March 14 · 6 min read
A section heading

Body copy rendered as a regular paragraph. Headings above render as real h1/h3 elements by default from their variant, and links stay anchors.

One deliberate exception: label-* defaults to span, not <label>. The type scale gets reused for lots of non-form UI text (buttons, tabs, chips, badges), and a real <label> carries form-control association semantics that would be wrong most of the time. Pass as="label" explicitly when a label-* variant is actually captioning a form field.

Margins are reset to 0; spacing between text blocks is yours to lay out (the demo above uses a flex column with a gap).