ReferenceTypography tokens
Rich text from a CMS, Markdown, or MDX arrives as bare HTML elements with no
classes. Add .prose to the element that holds it, and the headings,
paragraphs, lists, tables, code, quotes, rules, figures, and keys inside are
styled from Roadie tokens, and em, i, and cite show in Intermission's
italic face. The class ships in @oztix/roadie-core/css, so it
needs no import of its own.
In React, the Prose component adds the class and sets
its size.
Element rules sit inside :where() in the components layer. A utility on a
child, such as text-subtle on a paragraph, always wins over the sheet.
Space only goes above an element, never below, so a block's first child sits
flush with the top of its container. Every gap is a multiple of
--prose-flow, which is 1.25em by default. The property is registered, so
the em resolves once, at the prose body size, and a larger heading doesn't
bring a larger gap. Space above a heading runs from 1.2 flows for h5 and h6
to 3 flows for h1, and the block after it sits half a flow below, so each
heading reads as part of the section it opens.
Each direct child of .prose is capped at --prose-measure, which is 65ch
by default. The property is registered, so ch resolves once, at the prose
body size, rather than at each heading's size. Set it to another length to
change the cap, or to none to remove it.
Add .prose-bleed to a direct child that should span the full width, such as
a wide image or a table.
Tables shrink to fit their content. Wrap a table that might be wider than its
container in .prose-scroll, which scrolls sideways instead of overflowing
the page. Each column in a scrolling table stays at least 9em wide, so when
the columns can't all fit, the table scrolls rather than squeezing text to a
word or two a line. A long cell wraps at the prose measure. Inline code in a
scrolling table stays on one line, so a token such as rounded-sm never
splits. Outside .prose-scroll, inline code still breaks where it must, so the
table fits its column.
The Prose component wraps bare tables in
.prose-scroll for you, and makes each one reachable with the keyboard while it
overflows. With the class alone, use
useScrollRegion for that.
Add .not-prose or data-not-prose to an element inside .prose to keep the
sheet away from it and everything inside it. Use it around components,
previews, and anything else that brings its own styles. An escaped direct
child still takes its place in the rhythm and is still capped at
--prose-measure. Add .prose-bleed as well to let it run wider.
A .prose inside an escaped element stays unstyled, so put the escape around
the parts that need it, not around a whole region that also holds prose.
Set these on the .prose element to adjust the type without new classes.
| Variable | Default | Sets |
|---|---|---|
--prose-size | var(--text-base) | Body font size |
--prose-leading | var(--leading-prose) | Body line height |
--prose-flow | 1.25em | The gap every other gap derives from |
--prose-measure | 65ch | Maximum width of each direct child |
--prose-h1-size to --prose-h6-size | The text-display-ui-1 to -6 sizes | Heading font sizes |
--prose-h1-weight to --prose-h6-weight | The text-display-ui-1 to -6 weights | Heading font weights |
Colours come from the intent tokens, so .prose follows the intent and the
light or dark scheme it sits in, with no rules of its own for dark mode. Links
inherit the text colour with an accent underline, whatever intent they sit
in, and grow it into a tint on hover, the same as Link
at its default emphasis. Under forced colours, inline
code and code blocks get a border.
The sheet borrows its approach from typeset.css by shadcn, under the MIT licence.