Styling
Learn how to customize the appearance of Streamdown components.
Streamdown is designed to be flexible and customizable, allowing you to adapt its appearance to match your application's design system. This guide covers the various ways you can modify Streamdown's styles to suit your needs.
CSS Variables (Recommended)
Streamdown components are built using shadcn/ui's design system, which means they use CSS variables for theming. This is the simplest way to customize colors, borders, and other design tokens across all Streamdown components.
Setting Up Variables
Add or modify the CSS variables in your globals.css file:
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
}
}Variables Used by Streamdown
Streamdown components primarily use these CSS variables:
| Variable | Usage | Example Elements |
|---|---|---|
--primary | Links, accent colors | Links (<a>) |
--primary-foreground | Text on primary backgrounds | N/A |
--muted | Subtle backgrounds | Code blocks, table headers |
--muted-foreground | De-emphasized text | Blockquote text |
--border | Borders and dividers | Tables, horizontal rules, code blocks |
--ring | Focus rings on interactive elements | Buttons (copy, download) |
--radius | Border radius | Code blocks, tables, buttons |
Quick Theme Examples
Minimal Gray Theme:
:root {
--primary: 0 0% 20%;
--muted: 0 0% 96%;
--border: 0 0% 90%;
--radius: 0.25rem;
}Vibrant Blue Theme:
:root {
--primary: 217 91% 60%;
--muted: 214 100% 97%;
--border: 214 32% 91%;
--radius: 0.75rem;
}No Borders Theme:
:root {
--border: transparent;
--muted: 0 0% 98%;
--radius: 0rem;
}Custom Components
The most powerful way to customize Streamdown's appearance is by providing custom component overrides. This allows you to replace any Markdown element with your own React component while maintaining all of Streamdown's functionality.
Basic Usage
Pass custom components using the components prop:
<Streamdown
components={{
h1: ({ children }) => (
<h1 className="text-4xl font-bold text-blue-600">
{children}
</h1>
),
h2: ({ children }) => (
<h2 className="text-3xl font-semibold text-blue-500">
{children}
</h2>
),
p: ({ children }) => (
<p className="text-gray-700 leading-relaxed">
{children}
</p>
),
}}
>
{markdown}
</Streamdown>Available Components
You can override any of the following components:
- Headings:
h1,h2,h3,h4,h5,h6 - Text:
p,strong,em - Lists:
ul,ol,li - Links:
a - Code:
code,pre - Quotes:
blockquote - Tables:
table,thead,tbody,tr,th,td - Media:
img - Other:
hr,sup,sub,section
Component Props
Custom components receive all the props that the default components would receive, including:
children- The content to renderclassName- CSS class names (if applicable)node- The Markdown AST node (for advanced use cases)- Element-specific props (e.g.,
hreffor links,srcfor images)
<Streamdown
components={{
a: ({ href, children, ...props }) => (
<a
href={href}
className="text-purple-600 hover:text-purple-800 underline"
{...props}
>
{children} 🔗
</a>
),
}}
>
{markdown}
</Streamdown>Global CSS Targeting
For simpler styling needs, you can use global CSS to target Streamdown elements using the data-streamdown attribute. Every Streamdown element includes a unique data-streamdown attribute that makes it easy to apply custom styles.
Available Selectors
Target specific Streamdown elements using these data attributes:
/* 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"] { }
/* Text elements */
[data-streamdown="strong"] { }
[data-streamdown="link"] { }
[data-streamdown="inline-code"] { }
/* Lists */
[data-streamdown="ordered-list"] { }
[data-streamdown="unordered-list"] { }
[data-streamdown="list-item"] { }
/* Blocks */
[data-streamdown="blockquote"] { }
[data-streamdown="horizontal-rule"] { }
/* Code */
[data-streamdown="code-block"] { }
[data-streamdown="mermaid-block"] { }
/* 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"] { }
/* Other */
[data-streamdown="superscript"] { }
[data-streamdown="subscript"] { }Example Usage
Here's a practical example of customizing Streamdown styles with CSS:
/* Custom heading styles */
[data-streamdown="heading-1"] {
color: #1a202c;
border-bottom: 2px solid #e2e8f0;
padding-bottom: 0.5rem;
}
[data-streamdown="heading-2"] {
color: #2d3748;
margin-top: 2rem;
}
/* Custom link appearance */
[data-streamdown="link"] {
color: #3182ce;
text-decoration: none;
border-bottom: 1px solid #90cdf4;
transition: border-color 0.2s;
}
[data-streamdown="link"]:hover {
border-bottom-color: #3182ce;
}
/* Custom code block styling */
[data-streamdown="code-block"] {
border-radius: 0.5rem;
border: 1px solid #e2e8f0;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
/* Custom table styling */
[data-streamdown="table"] {
border-radius: 0.5rem;
overflow: hidden;
}
[data-streamdown="table-header"] {
background: linear-gradient(to bottom, #f7fafc, #edf2f7);
}
/* Custom blockquote styling */
[data-streamdown="blockquote"] {
background-color: #f7fafc;
border-left-color: #4299e1;
border-radius: 0.25rem;
}Scoped Styling
You can scope your styles to specific instances of Streamdown by using the className prop:
<Streamdown className="docs-content">
{markdown}
</Streamdown>/* Styles only apply to this specific instance */
.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;
}Combining Approaches
For maximum flexibility, you can combine both approaches - using custom components for structural changes and CSS for visual styling:
<Streamdown
className="custom-markdown"
components={{
h1: ({ children, ...props }) => (
<h1 {...props}>
<span className="heading-icon">📖</span>
{children}
</h1>
),
}}
>
{markdown}
</Streamdown>.custom-markdown [data-streamdown="heading-1"] {
display: flex;
align-items: center;
gap: 0.5rem;
}
.custom-markdown .heading-icon {
font-size: 1.5rem;
}Additional Styling Props
Beyond component overrides and CSS, Streamdown provides additional styling-related props:
Container Class Name
Use the className prop to add custom classes to the Streamdown container:
<Streamdown className="prose prose-lg dark:prose-invert max-w-none">
{markdown}
</Streamdown>Syntax Highlighting Themes
Customize code block appearance with Shiki themes:
<Streamdown
shikiTheme={['github-light', 'github-dark']}
>
{markdown}
</Streamdown>See the Code Blocks documentation for more details on syntax highlighting customization.
Best Practices
When customizing Streamdown styles, consider these best practices:
-
Start with CSS Variables - For most theming needs (colors, borders, radius), modifying CSS variables in
globals.cssis the simplest and most maintainable approach. -
Use
data-streamdownSelectors for Specific Elements - When you need to target individual elements without affecting the entire theme, use thedata-streamdownattribute selectors. -
Use Custom Components for Structural Changes - When you need to change the HTML structure or add wrapper elements, use the
componentsprop. -
Maintain Accessibility - Ensure your custom styles maintain proper color contrast, focus states, and semantic HTML structure.
-
Test During Streaming - Verify that your custom styles work well with incomplete content during streaming.
-
Scope Your Styles - Use the
classNameprop to scope styles and avoid conflicts with other parts of your application. -
Preserve Animations - Streamdown includes built-in animations for smooth streaming. Be careful not to override animation-related classes unless intentional.
Styling Priority
The three styling approaches have the following priority (highest to lowest):
- Custom Components - Complete control over rendering
- CSS via
data-streamdownselectors - Element-specific styling - CSS Variables - Global theme tokens