Skip to content
misoto22 design

Surfaces

Article

The long-form reading surface — everything a Markdown pipeline emits, in this system’s type.

When to reach for it

A post, a changelog entry, a document. Not for interface copy: a paragraph inside a card is a paragraph, and this is a whole reading column with its own rhythm.

Examples

default

A heading, in the editorial serif

The opening paragraph is marked, not guessed — a stylesheet that decides whatever came first is a standfirst gets it wrong the moment a post opens on an image.

Body copy sits on the reading measure and nothing wider, with a link, some inline code and a strong word in it.

Depth is a hairline and a change of ground, never a blur.The White Reset, law 2
  • The list marker is a hairline dash, not a filled disc.
  • A filled circle in this system means a status dot.

Notes

The long-form reading surface.

Everything a Markdown pipeline can emit — headings, prose, lists, tables, quotations, code, figures, footnotes, MathML — set in this system's type, colour and rules. The styles live in article.css rather than in a class string, because the input is not JSX: there is no component to hang a class on when the markup arrived as a string, so the contract has to be the element names themselves.

That file is published on its own as @misoto22/design/article.css, so a site with its own Markdown pipeline can take the reading surface without taking the components — which is the case this exists for. Three sites hand-rolling a prose stylesheet is three prose stylesheets that drift.

Composable either way: pass html for a rendered string, or children for real elements. A post that mixes the two — prose with a Diagram dropped into the middle — renders its blocks in order and gives each one an Article; a component inside keeps its own classes, because every rule in the layer is a bare element selector that a utility outranks.

Props

Article props
PropTypeDefaultDescription
as'article' | 'div' | 'section'The element to render. `article` by default; pass `div` for a fragment.
htmlstringRendered HTML from a Markdown or MDX pipeline. Trusted markup only. This sets `dangerouslySetInnerHTML`, so it must come from content you control — a repository's own posts, a CMS you author — and never from a reader. Untrusted Markdown has to be sanitised before it reaches here; that is a pipeline decision, not a component one, and a sanitiser bolted on inside a styling primitive would be the wrong place to make it and the easiest place to get it wrong.

Also accepts everything in HTMLAttributes<HTMLElement>. Those are forwarded to the underlying element and are not listed row by row.

Accessibility

  • An <article> by default, so the piece is a landmark a reader can jump to.
  • Every heading carries scroll-margin, so an anchored link does not park the heading under a fixed masthead.
  • The styles are element selectors at low specificity, so a component dropped inside keeps its own.