Blog post title
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.
import { Typography } from "@brijbyte/md3-react/typography";
@import "@brijbyte/md3-react/typography.css";
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.
Body large
Body medium
Body small
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.
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 h1 — title-* renders
h3–h6, 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.
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).