Skip to main content
Streamdown’s visual appearance is built on shadcn/ui design tokens and Tailwind CSS utility classes. There are three complementary ways to customize it — you can use them independently or in combination. All colors, borders, and radii in Streamdown resolve from the same CSS custom properties that shadcn/ui uses. Defining these variables in your globals.css is the most concise way to retheme the entire component.

Variables used by Streamdown

VariableWhere it appears
--primaryLink color (<a> elements)
--mutedInline code background, table header background, code block background
--muted-foregroundBlockquote text, de-emphasized labels
--borderTable borders, horizontal rules, code block borders
--ringFocus rings on copy / download buttons
--radiusBorder radius on code blocks, tables, and buttons
--sidebarMermaid diagram container background
--backgroundInner panel of Mermaid containers

Setting up variables

Add the variables to your globals.css inside a @layer base block so Tailwind can apply them at the correct cascade layer:
app/globals.css
@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --primary: 222.2 47.4% 11.2%;
    --primary-foreground: 210 40% 98%;
    --muted: 210 40% 96.1%;
    --muted-foreground: 215.4 16.3% 46.9%;
    --border: 214.3 31.8% 91.4%;
    --ring: 222.2 84% 4.9%;
    --radius: 0.5rem;
    --sidebar: 0 0% 98%;
  }

  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;
    --primary: 210 40% 98%;
    --primary-foreground: 222.2 47.4% 11.2%;
    --muted: 217.2 32.6% 17.5%;
    --muted-foreground: 215 20.2% 65.1%;
    --border: 217.2 32.6% 17.5%;
    --ring: 212.7 26.8% 83.9%;
    --sidebar: 222.2 84% 6%;
  }
}

Quick theme examples

app/globals.css
:root {
  --primary: 0 0% 20%;
  --muted: 0 0% 96%;
  --border: 0 0% 90%;
  --radius: 0.25rem;
}

2. Importing the stylesheet

Streamdown ships a small stylesheet for animation keyframes. Import it once at the root of your application:
app/layout.tsx
import 'streamdown/styles.css';
The stylesheet defines three @keyframes rules (sd-fadeIn, sd-blurIn, sd-slideUp) and the [data-sd-animate] selector that the animation plugin uses. You do not need to import it if you are not using the animated prop.

3. Tailwind CSS integration

Standard setup

Streamdown’s internal classes use standard Tailwind utility names. If your project already has Tailwind configured, no additional setup is required — the classes will be included in your build as long as Streamdown’s source is included in the Tailwind content scan. For Tailwind v4, add Streamdown’s package to the @source directive:
app/globals.css
@import "tailwindcss";
@source "../../node_modules/streamdown";

Tailwind prefix support

If your Tailwind v4 config uses the prefix() function, pass the same prefix to the prefix prop so Streamdown’s internal class names match:
app/page.tsx
<Streamdown prefix="tw">{markdown}</Streamdown>
app/globals.css
@import "tailwindcss" prefix(tw);
The prefix prop also applies to class names you pass via the className prop. Pass unprefixed class names — Streamdown adds the prefix for you.

4. Global CSS with data-streamdown selectors

Every element rendered by Streamdown carries a data-streamdown attribute. Use these attributes in your global CSS to style individual element types without replacing the entire component.

Available selectors

styles/streamdown.css
/* Headings */
[data-streamdown="heading-1"] { }
[data-streamdown="heading-2"] { }
[data-streamdown="heading-3"] { }
[data-streamdown="heading-4"] { }
[data-streamdown="heading-5"] { }
[data-streamdown="heading-6"] { }

/* Inline text */
[data-streamdown="strong"] { }
[data-streamdown="link"] { }
[data-streamdown="inline-code"] { }
[data-streamdown="superscript"] { }
[data-streamdown="subscript"] { }

/* Lists */
[data-streamdown="ordered-list"] { }
[data-streamdown="unordered-list"] { }
[data-streamdown="list-item"] { }

/* Block elements */
[data-streamdown="blockquote"] { }
[data-streamdown="horizontal-rule"] { }

/* Code blocks */
[data-streamdown="code-block"] { }
[data-streamdown="code-block-header"] { }
[data-streamdown="code-block-body"] { }
[data-streamdown="code-block-actions"] { }
[data-streamdown="code-block-copy-button"] { }
[data-streamdown="code-block-download-button"] { }

/* Mermaid diagrams */
[data-streamdown="mermaid"] { }
[data-streamdown="mermaid-block"] { }
[data-streamdown="mermaid-block-actions"] { }

/* Tables */
[data-streamdown="table-wrapper"] { }
[data-streamdown="table"] { }
[data-streamdown="table-header"] { }
[data-streamdown="table-body"] { }
[data-streamdown="table-row"] { }
[data-streamdown="table-header-cell"] { }
[data-streamdown="table-cell"] { }
[data-streamdown="table-fullscreen"] { }

/* Images */
[data-streamdown="image-wrapper"] { }
[data-streamdown="image"] { }
[data-streamdown="image-fallback"] { }

/* Link safety modal */
[data-streamdown="link-safety-modal"] { }
styles/streamdown.css
[data-streamdown="heading-1"] {
  border-bottom: 2px solid #e2e8f0;
  padding-bottom: 0.5rem;
}

[data-streamdown="link"] {
  color: #3182ce;
  text-decoration: none;
  border-bottom: 1px solid #90cdf4;
}

[data-streamdown="link"]:hover {
  border-bottom-color: #3182ce;
}

[data-streamdown="blockquote"] {
  background-color: #f7fafc;
  border-left-color: #4299e1;
}

Scoping styles to a single instance

Use the className prop together with a descendant selector to apply styles only to a specific Streamdown instance:
app/page.tsx
<Streamdown className="docs-content">{markdown}</Streamdown>
styles/streamdown.css
.docs-content [data-streamdown="heading-1"] {
  font-family: 'Inter', sans-serif;
  letter-spacing: -0.02em;
}

.docs-content [data-streamdown="code-block"] {
  font-family: 'Fira Code', monospace;
}

5. Custom components (structural changes)

When CSS alone is not enough — for example, when you need to add wrapper elements, change the HTML tag, or inject React components — use the components prop. See the Components page.

Styling priority

When multiple approaches target the same element, the effective priority is:
  1. Custom components — full control; replaces all default output including styles
  2. data-streamdown CSS selectors — element-specific visual overrides
  3. CSS variables — global design tokens for colors, radius, and spacing

Best practices

  • Start with CSS variables for broad color and spacing changes.
  • Use data-streamdown selectors when you need to target specific element types without replacing their default structure.
  • Use custom components only when you need structural or behavioral changes.
  • Test your styles with isAnimating={true} and partial content to verify they work correctly during streaming.
  • Use the className prop to scope styles and avoid leaking them into other parts of your UI.

Build docs developers (and LLMs) love