Prose
FreeSpacing, a readable measure and quiet links for long-form markup you do not control, such as a Markdown render, release notes or a legal page.
pnpm dlx shadcn@latest add https://caliperui.site/r/prose.jsonRelease notes, October 2026
Eleven parts shipped, and every dialog now returns focus to where you were.
What changed
The toggle group moves with the arrow keys and is one tab stop. Install it with npx shadcn add @caliper/toggle.
Upgrade notes
- Dialog actions are ordered cancel first, then the action
- No breaking changes to props
We replaced the hand-rolled confirm in three places and deleted 400 lines.
When to use #
Use it for
- Rendered Markdown, CMS content and release notes.
- Docs that carry headings, lists, quotes and code together.
Skip it when
- Interface text; style it with the type scale directly.
- Marketing pages with their own layout; use the blocks.
Decisions #
Why it is built this way, so you know what to keep when you change your copy.
Styling
- Product 14/22 and reading 17/1.7
- Product size matches the interface around it; reading size is the article template's, for pages people sit with.
- Links stay underlined
- Colour is never the only cue, and the underline thickens on hover so the target is clear without changing the text colour.
Installation #
pnpm dlx shadcn@latest add https://caliperui.site/r/prose.json
Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above.
import { useState } from "react" import { Prose } from "@/components/ui/prose" import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle" export function ProseDemo() { const [size, setSize] = useState(["product"]); return ( <div className="grid gap-5"> <ToggleGroup type="single" label="Text size" value={size} onValueChange={setSize} className="justify-self-start"> <ToggleGroupItem value="product" size="sm">Product</ToggleGroupItem> <ToggleGroupItem value="reading" size="sm">Reading</ToggleGroupItem> </ToggleGroup> <Prose size={size[0] === "reading" ? "reading" : "product"}> <h1>Release notes, October 2026</h1> <p>Eleven parts shipped, and every dialog now returns focus to where you were.</p> <h2>What changed</h2> <p>The <a href="#changes">toggle group</a> moves with the arrow keys and is one tab stop. Install it with <code>npx shadcn add @caliper/toggle</code>.</p> <h3>Upgrade notes</h3> <ul> <li>Dialog actions are ordered cancel first, then the action</li> <li>No breaking changes to props</li> </ul> <blockquote>We replaced the hand-rolled confirm in three places and deleted 400 lines.</blockquote> </Prose> </div> ); }
API reference #
Prose
component
Also accepts the native props of its root element and a ref.
Accessibility #
It is built on native elements, so roles and focus come from the browser.
No custom key handling; Tab and the native activation keys do the work.
Motion #
It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.