Prose

The reading type. Wrap a document, CMS rich text, rendered Markdown or plain JSX, and its bare headings, lists, quotes, code and tables are typeset on Koala's tokens, with one size prop.

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add prose

Usage#

usage.tsxTSX
import { Prose } from "@/components/ui/prose"export function Article({ html }: { html: string }) {  return <Prose size="lg" dangerouslySetInnerHTML={{ __html: html }} />}

Sizes#

The size picks the type and the rhythm together. sm is the 14px body of the product UI (a comment, a task description, what a RichTextEditor wrote); md is docs and release notes; lg is long-form reading at 17px, for an article at a ~42rem measure.

Rich text from a CMS#

A CMS, a Markdown renderer or a Tiptap export hands you a string of bare HTML. Set it on Prose and it is typeset as it is: no class to add to the content.

Elements#

Ordered lists carry tabular markers, inline code keeps the global chip, a pre is a muted block that scrolls on its own, a table scrolls inside the column instead of the page, and a picture gets the corner radius and the image outline. Media take a wider step than copy, so they read as breaks.

Components inside#

Prose styles bare elements. An anchor or image that carries a class is a component, so it keeps its own look: a Link or a Button dropped into the copy is never underlined or restyled.

As child#

Pass asChild to put the styling on your own element, an article or a section, instead of a wrapping div.

article.tsxTSX
<Prose asChild size="lg">  <article>    <h2>Tokens over values</h2>    <p>A card does not know it is twelve pixels of radius; it knows it uses the surface radius.</p>  </article></Prose>

FAQ#

No. Prose is one tv recipe on Koala's own tokens: the body is the `--body` reading ink, headings and bold lift to `--foreground`, list markers step down to `--muted-foreground`, links turn `--link` on hover. It re-themes across light, cream, dark and moonlight with no plugin.