CSS theming

Customize Rho's visuals — CSS variables are the preferred path; class overrides and full custom CSS also supported.


Importing default CSS

import '@rho/md/css';

Or:

<link rel="stylesheet" href="path/to/@rho/md/css/stl-md.css">

The default CSS includes all DSL styles + light/dark themes + responsive breakpoints.


CSS variables (preferred customization)

Rho exposes all customizable colors / spacing / typography as CSS variables, scoped to .markdown-body:

.markdown-body {
  /* === Color base === */
  --bg-color: #ffffff;
  --text-color: #1a1a2e;
  --muted-color: #6b7280;
  --border-color: #e5e7eb;
  --code-bg: #f8f8f8;

  /* === Accent palette (6 colors) === */
  --accent-blue: #2563eb;
  --accent-red: #dc2626;
  --accent-green: #16a34a;
  --accent-yellow: #ca8a04;
  --accent-purple: #9333ea;
  --accent-gray: #6b7280;

  /* === Spacing === */
  --spacing-xs: 4px;
  --spacing-sm: 8px;
  --spacing-md: 16px;
  --spacing-lg: 24px;
  --spacing-xl: 32px;

  /* === Typography === */
  --font-body: -apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif;
  --font-mono: 'JetBrains Mono', monospace;
  --font-size-base: 16px;
  --line-height-base: 1.65;

  /* === Border radius === */
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;
}

Change brand colors — one line:

.markdown-body {
  --accent-blue: #007aff;     /* iOS blue */
  --accent-purple: #a020f0;   /* Custom purple */
}

→ Every callout / card / annotation using accent=blue or accent=purple updates accordingly.


Dark theme

Rho ships a default dark theme. Two ways to trigger:

Option A: data-theme attribute

<div class="markdown-body" data-theme="dark">
  ...
</div>

Option B: follow system preferences

@media (prefers-color-scheme: dark) {
  .markdown-body {
    --bg-color: #0f1115;
    --text-color: #e8ecf1;
    --muted-color: #8a93a3;
    --border-color: #2a2f3c;
    --code-bg: #1c2030;

    --accent-blue: #60a5fa;
    --accent-red: #f87171;
    --accent-green: #34d399;
    --accent-yellow: #fbbf24;
    --accent-purple: #c084fc;
    --accent-gray: #94a3b8;
  }
}

CSS class hooks

Rho's HTML uses stable class names so you can completely override default styles:

Class Maps to
.markdown-body container
.rho-callout / .rho-callout-info / .rho-callout-warn / .rho-callout-zen / etc. Callout
.rho-layout-grid / .rho-card / .rho-card-blue / etc. Layout
.rho-annotate / .rho-anno / .rho-anno-red / etc. Annotate
.rho-tabs / .rho-tabs-bar / .rho-tab-btn / .rho-tab-active / .rho-tab-panel Tabs
.rho-stepper / .rho-stepper-progress / .rho-step-marker / .rho-step-active / .rho-step-panel / .rho-stepper-nav Stepper
.rho-timeline / .rho-event / .rho-event-blue / etc. Timeline
.rho-modal-trigger / .rho-modal Modal
.rho-interact / .rho-slider / .rho-input / .rho-select / .rho-toggle / .rho-button Interact controls
.rho-template-output template output
.rho-vega-chart Vega-Lite chart container
.rho-svg SVG scene container

Full class list in source (the CSS file itself).


Custom callout types

Rho ships 8 built-in callout types (INFO/WARN/ZEN + 5 GFM). Add your own:

.markdown-body .rho-callout-custom-tip {
  --callout-bg: rgba(255, 200, 0, 0.1);
  --callout-border: orange;
  --callout-icon-color: orange;
}

.markdown-body .rho-callout-custom-tip .rho-callout-icon::before {
  content: "💡";
}

Then in markdown > [!CUSTOM_TIP] uses this style (Rho doesn't recognize but preserves the type string in class).

Note: > [!CUSTOM_TIP] shows as [!CUSTOM_TIP] literal in non-supporting readers — non-standard types break plain-text fallback elegance. Recommendation: stick to the 8 standard types.


Per-block style overrides

/* Change layout grid default gap */
.markdown-body .rho-layout-grid {
  gap: 32px;
}

/* Change tab bar color */
.markdown-body .rho-tabs-bar {
  background: linear-gradient(to right, #007aff, #5856d6);
}

/* Change slider track color */
.markdown-body .rho-slider input[type="range"] {
  accent-color: #ff3b30;
}

Tailwind / CSS-in-JS integration

Tailwind

Rho CSS doesn't conflict with Tailwind (different namespaces). In a Tailwind project:

  1. import '@rho/md/css' for Rho default styles
  2. Use Tailwind for your page / wrapper
  3. Inside .markdown-body, Rho CSS rules; outside, Tailwind

If you want Rho to use your Tailwind colors:

@layer components {
  .markdown-body {
    --accent-blue: theme('colors.blue.600');
    --accent-red: theme('colors.red.600');
    --bg-color: theme('colors.white');
    --text-color: theme('colors.gray.900');
  }
}

CSS-in-JS (Emotion / styled-components)

import { css, Global } from '@emotion/react';

const rhoTheme = css`
  .markdown-body {
    --accent-blue: ${myTheme.brand};
    --accent-green: ${myTheme.success};
    /* ... */
  }
`;

<>
  <Global styles={rhoTheme} />
  <div className="markdown-body">{rhoHTML}</div>
</>

Fully custom styles (skip default CSS)

// Don't import '@rho/md/css'
import { hydrateAll, renderRho } from '@rho/md';

Then write fully your own .rho-* class CSS (use the default CSS file as a starting reference). Suitable for:

  • Deep integration with an existing design system
  • Fully custom visuals
  • Removing default Rho appearance overhead

CSS file location / size

@rho/md/css/stl-md.css        ← Full CSS (~30 KB unminified)
@rho/md/css/stl-md.min.css    ← Minified (~8 KB)

See also