Typeset

Purpose and Scope

Typeset is the shadcn styling system for rendered HTML and markdown. It addresses the common problem where a markdown renderer returns plain headings, paragraphs, lists, tables, rules, and code blocks, leaving every product surface to restyle the same elements independently. The official Typeset page frames this as a repeated rhythm problem across blogs, documentation, and chat applications. Instead of making authors maintain scattered element selectors, Typeset gives the project one owned CSS file and a container class that applies consistent typography inside a chosen content boundary.

Sources: apps/v4/content/docs/(root)/typeset.mdx

The important ownership model is that Typeset is not a remote theme that hides its rules. The CSS file is copied into the application, imported after Tailwind, and edited directly when the project needs different behavior. That fits the repository’s broader open-code philosophy: users start from a polished default, then make the implementation their own. In practice, this makes Typeset useful for teams that need predictable markdown styling but still want their local design tokens, fonts, radius, and dark mode decisions to remain the source of truth.

Sources: apps/v4/content/docs/(root)/typeset.mdx

Relevant Source Files

  • apps/v4/content/docs/(root)/typeset.mdx - Defines the reader-facing Typeset guide, including the problem statement, rhythm principles, feature list, builder workflow, CSS import pattern, wrapper markup, custom variables, dark-mode behavior, responsive sizing, and streaming guidance.
  • packages/shadcn/src/commands/build.ts - Implements the registry build command that turns registry definitions into distributable registry item JSON files and a registry catalog, which matters when a team packages Typeset-related files or presets through a registry workflow.
  • packages/shadcn/src/commands/view.ts - Implements the registry view command that resolves item addresses against configured registries and prints the resolved JSON payload, which is useful for inspecting registry-published assets before installation or automation.

Core Primitives

A typeset is a small preset class layered on top of the base container. The base container enables the element styling, while the preset records the rhythm and font choices for a specific context such as documentation, an article page, or a compact chat bubble. The documentation deliberately narrows the tuning surface to three rhythm values: size, leading, and flow. Heading scale, list indentation, rule spacing, and spacing around blocks derive from those controls, so authors can change the feel of a whole document without editing every HTML element by hand.

Sources: apps/v4/content/docs/(root)/typeset.mdx

@import 'tailwindcss';
@import './typeset.css';
<div className="typeset typeset-docs">
  <YourMarkdownRenderer>{content}</YourMarkdownRenderer>
</div>

The base variables are intentionally readable. The body, heading, and monospace font variables let Typeset inherit from the surrounding application or point to named font variables. The size variable controls base text size, leading controls line height, and flow controls spacing between blocks. The docs also state that Typeset does not impose a maximum width, because layout ownership belongs outside the typography system. That distinction matters: use the surrounding page, card, article shell, or chat message component to control measure, then let Typeset control the internal rhythm of generated content.

Sources: apps/v4/content/docs/(root)/typeset.mdx

.typeset {
  --typeset-font-body: inherit;
  --typeset-font-heading: var(--font-heading);
  --typeset-font-mono: var(--font-mono);
  --typeset-size: 1em;
  --typeset-leading: 1.75;
  --typeset-flow: 1.25em;
}

Building and Applying a Typeset

The recommended authoring path starts in the Typeset builder. The builder lets a developer pick fonts and rhythm, then preview the result across realistic content such as documentation, chat, and article layouts. The output is practical rather than abstract: a typeset CSS file, framework font setup guidance, a preset class with the selected values, and the wrapper markup. After copying the CSS file next to the main stylesheet and importing it after Tailwind, rendered markdown only needs the base container and the selected preset class around it.

Sources: apps/v4/content/docs/(root)/typeset.mdx

Custom typesets are appropriate when one application has multiple reading contexts. A docs page may need a larger measure and steadier vertical rhythm, while a streaming assistant answer may need to fit inside a smaller bubble and align with surrounding interface text. Because Typeset follows the container, the same system can scale with the component that owns it. The documentation also notes a small readability bump on smaller screens, so authors should preview compact layouts instead of assuming desktop rhythm is the only target.

Sources: apps/v4/content/docs/(root)/typeset.mdx

System-to-Code Mapping

Typeset itself is documented as a local CSS asset, but teams can also distribute Typeset-related files through the registry system when they maintain internal presets, docs shells, or markdown renderers. The build command accepts a registry file path, an output directory, and a working directory. It validates those options, runs a preflight, loads registry definitions including includes, creates per-item registry JSON payloads, and writes either a generated catalog or a copied registry file. That command is the publication step for shareable project assets, not the runtime step for applying typography.

Sources: packages/shadcn/src/commands/build.ts

The view command covers the inspection side of that workflow. It accepts one or more item addresses, loads environment files, creates a defaulted shadow configuration, and then attempts to merge in a full project configuration when available. It can work with a partial components configuration, ensures registries referenced by the requested items are available without writing the file, validates the registry configuration early, fetches the resolved items, and prints formatted JSON. For Typeset adopters, this is a useful way to verify exactly what a registry item would deliver before installing or scripting around it.

Sources: packages/shadcn/src/commands/view.ts

AreaSource-backed behavior
Local stylingThe Typeset guide describes copying a CSS file into the app and importing it after Tailwind.
PresetsThe guide shows a base container plus named preset classes for different contexts.
Theme integrationThe guide states that colors, fonts, radius, and dark mode follow application tokens.
Registry publishingThe build command writes registry item JSON files and a registry catalog or copied registry file.
Registry inspectionThe view command resolves item addresses and prints the registry item payload.

Streaming, Tables, Dark Mode, and Opt-Out Decisions

Typeset is designed for content that changes over time, especially streaming chat. The documentation calls out that when a new block arrives, earlier blocks should not suddenly switch margins, borders, or styles. That is a subtle but important constraint for AI interfaces: typography should not cause visual jumps as paragraphs and lists accumulate. The same system also covers tables and other rendered HTML elements, which keeps markdown output cohesive across long-form pages and generated responses rather than forcing each renderer integration to maintain its own element-by-element stylesheet.

Sources: apps/v4/content/docs/(root)/typeset.mdx

Dark mode is handled through the application theme rather than a separate Typeset-only palette. The Typeset feature list says colors, fonts, and radius come from the app, and dark mode follows the same tokens. That means the correct next step for color changes is usually to adjust the project theme tokens, not to fork every Typeset selector. Conversely, when a surface should not receive Typeset styling, the practical opt-out is architectural: do not wrap that content in the Typeset container, or use a different preset that matches the surrounding component.

Sources: apps/v4/content/docs/(root)/typeset.mdx

Next Steps

Start by generating or copying a Typeset file, importing it after Tailwind, and wrapping one markdown surface with the base container plus a named preset. Tune only size, leading, and flow first; if the result still feels wrong, then adjust fonts, theme tokens, measure, or local CSS rules. If your team wants to share the same preset across projects, package the CSS and wrapper convention as a registry item, build the registry output, and inspect the item payload before publishing it for other applications.

Sources: apps/v4/content/docs/(root)/typeset.mdx, packages/shadcn/src/commands/build.ts, packages/shadcn/src/commands/view.ts