Repo

Usage

Wrap any block of HTML content with .prose to get styled headings, paragraphs, lists, blockquotes, links, code blocks, and media.

Article Title

Body text with links and inline code.

  • List items
  • Are styled automatically
Blockquotes get a left border.
<article class="prose">
<h1>Article Title</h1>
<p>Body text with <a href="#">links</a> and <code>inline code</code>.</p>
<ul>
  <li>List items</li>
  <li>Are styled automatically</li>
</ul>
<blockquote>Blockquotes get a left border.</blockquote>
</article>

Kitchen sink

Heading 1

Paragraph text with a link, bold, italic, and inline code.

Heading 2

Another paragraph to show flow spacing between elements. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Heading 3

Heading 4

  • Unordered list item one
  • Item two
    • Nested item
    • Another nested item
      • Deeply nested
  • Item three
  1. Ordered list item one
  2. Item two
    1. Nested ordered
    2. Another nested
      1. Deeply nested
  3. Item three
A blockquote for emphasis or attribution. Styled with a left border and italic text.
// Code block
const greeting = 'Hello, world!'
console.log(greeting)

Content after a horizontal rule.

Placeholder image
<article class="prose">
  <h1>Heading 1</h1>
  <p>Paragraph text with <a href="#">a link</a>, <strong>bold</strong>, <em>italic</em>, and <code>inline code</code>.</p>
  <h2>Heading 2</h2>
  <p>Another paragraph to show flow spacing between elements. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
  <h3>Heading 3</h3>
  <h4>Heading 4</h4>
  <ul>
    <li>Unordered list item one</li>
    <li>Item two
      <ul>
        <li>Nested item</li>
        <li>Another nested item
          <ul>
            <li>Deeply nested</li>
          </ul>
        </li>
      </ul>
    </li>
    <li>Item three</li>
  </ul>
  <ol>
    <li>Ordered list item one</li>
    <li>Item two
      <ol>
        <li>Nested ordered</li>
        <li>Another nested
          <ol>
            <li>Deeply nested</li>
          </ol>
        </li>
      </ol>
    </li>
    <li>Item three</li>
  </ol>
  <blockquote>A blockquote for emphasis or attribution. Styled with a left border and italic text.</blockquote>
  <pre><code>// Code block
const greeting = 'Hello, world!'
console.log(greeting)</code></pre>
  <hr />
  <p>Content after a horizontal rule.</p>

</article>

Inverted

Add .inverted when prose sits on a dark surface — such as one filled with --color-text. It swaps the text/background colour mapping so links, code, and body copy stay readable.

Inverted prose

Body text with links and inline code on a dark surface.

Blockquotes stay legible too.
<div style="background: var(--color-text); padding: var(--space-md); border-radius: var(--radius-lg);">
<article class="prose inverted">
  <h2>Inverted prose</h2>
  <p>Body text with <a href="#">links</a> and <code>inline code</code> on a dark surface.</p>
  <blockquote>Blockquotes stay legible too.</blockquote>
</article>
</div>

What it styles

Overriding styles

All prose styles are wrapped in :where(.prose), giving them zero specificity. Any single class — a ZUI utility like .mt-lg or .zui-text-2, or one of your own — overrides the prose defaults on that element, no !important needed. Prose still overrides component styles (zui.components) because layer order takes precedence over specificity.

<article class="prose">
  <h2>Default prose heading</h2>
  <h2 class="zui-text-6 mt-2xl">Bigger, with extra space above</h2>
</article>

Custom properties

Set these on :root, on a wrapper, or on the element. See Component custom properties.

Property Default Description
--prose-color var(--color-text) Text colour
--prose-accent-color var(--color-theme) h2 colour
--prose-link-color var(--color-text) Link colour
--prose-link-color-decoration oklch(from var(--color-text) l c h / 50%) Link underline colour
--prose-link-color-decoration-hover oklch(from var(--color-text) l c h / 90%) Link underline colour on hover
--prose-code-color oklch(from var(--color-text) calc(l + 0.1) c h) Code text colour
--prose-code-bg-color oklch(from var(--color-background) calc(l + 0.1) c h) Code background colour
--prose-scroll-margin 1.5rem Space above an element when you link to its id
--prose-font-size var(--step-0) Body text font size
--prose-h1-font-size var(--step-3) h1 font size
--prose-h2-font-size var(--step-2) h2 font size
--prose-h3-font-size var(--step-1) h3 font size
--prose-h4-font-size var(--step-0) h4 font size
--prose-code-font-size var(--step--1) Inline code font size
--prose-code-radius var(--radius-md) Inline code border radius
--prose-pre-font-size var(--step--2) Code block font size
--prose-pre-radius var(--radius-xl) Code block border radius
--prose-pre-padding var(--space-2xs) var(--space-xs) Code block padding
:root {
  --prose-h1-font-size: var(--step-5);
  --prose-font-size: var(--step-1);
}

.prose.inverted sets its own colours, so a colour you set on :root doesn't change inverted prose.

Modifiers

.prose.invertedInverted colour scheme for dark backgrounds
.prose.max-width-pLimits paragraph width to 65ch for readability

Theme

Copy this CSS to your project: