Skip to main content

Theming & Customization

The renderer uses CSS custom properties (design tokens) prefixed with --omnispec- for all visual styling. This enables white-labeling without modifying source code.

In the free core (@apiboost/omnispec) you control the theme two ways:

  1. theme.base — pick light, dark, or auto (and optionally a built-in toggle). Covered next.
  2. Raw --omnispec-* CSS-variable overrides — set any of the design tokens below directly on .omnispec-root (or a host element) with plain CSS. This is the free white-labeling path and is documented under CSS Variable Overrides (Free).
Pro

The programmatic theme.overrides prop — passing an arbitrary token map to <OmniSpecRenderer> — requires Apiboost OmniSpec Pro. In the free core, theme.overrides is silently ignored (no error); set the same --omnispec-* tokens with a CSS rule instead (see CSS Variable Overrides (Free)). The token reference table below documents every available token for either approach.

Built-in Themes

Two themes are included: light and dark.

<OmniSpecRenderer spec={url} theme={{ base: 'light' }} />
<OmniSpecRenderer spec={url} theme={{ base: 'dark' }} />

Theme Modes

The theme.base prop supports three values:

Controlled Mode ('light' or 'dark')

The parent application controls the theme. No built-in toggle is rendered. This is the default behavior for embedded use cases where the host app already has its own theme switching:

// Parent app controls the theme
const [mode, setMode] = useState<'light' | 'dark'>('light')

<OmniSpecRenderer spec={url} theme={{ base: mode }} />

Auto Mode ('auto')

The renderer detects the user's system preference (prefers-color-scheme) and manages theme state internally. A floating toggle button (sun/moon icon) appears in the bottom-right corner:

<OmniSpecRenderer spec={url} theme={{ base: 'auto' }} />

This is ideal for standalone deployments where the renderer is the primary page content.

Hiding the Toggle

To use auto-detection without showing the built-in toggle (e.g., your app provides its own toggle):

<OmniSpecRenderer
spec={url}
theme={{
base: 'auto',
themeToggle: false,
}}
/>

Listening to Theme Changes

Use onThemeChange to sync external UI with the renderer's resolved theme:

<OmniSpecRenderer
spec={url}
theme={{
base: 'auto',
onThemeChange: (theme) => {
document.documentElement.setAttribute('data-theme', theme)
},
}}
/>

Mode Comparison

basethemeToggleBehavior
'light' / 'dark'ignoredControlled by developer, no toggle
'auto'true (default)System preference + built-in toggle
'auto'falseSystem preference, no toggle, use onThemeChange

CSS Variable Overrides (Free)

Every visual detail is driven by the --omnispec-* design tokens listed in the reference table below. In the free core you re-skin the renderer by setting those tokens with plain CSS on the .omnispec-root class (or any ancestor). This is the free white-labeling path and needs no props:

.omnispec-root {
--omnispec-color-primary: #8b5cf6;
--omnispec-color-primary-hover: #7c3aed;
--omnispec-color-primary-text: #ffffff;
--omnispec-nav-accent: #8b5cf6;
--omnispec-border-radius: 0.5rem;
}

Only declare the tokens you want to change — everything else inherits from the active theme.base.

Per-Mode Overrides (Light vs Dark)

Because they are ordinary CSS custom properties, you can scope overrides per mode with a prefers-color-scheme media query. This works with any theme.base, including 'auto':

.omnispec-root {
--omnispec-color-primary: #7c3aed;
}

@media (prefers-color-scheme: dark) {
.omnispec-root {
--omnispec-color-primary: #a78bfa;
--omnispec-bg-primary: #1a1025;
--omnispec-nav-bg: #2d1b4e;
}
}

If you control the mode yourself (rather than 'auto'), toggle a class or data- attribute on your wrapper and scope the tokens to it:

.omnispec-root[data-mode='light'] {
--omnispec-bg-primary: #faf5ff;
--omnispec-color-primary: #7c3aed;
--omnispec-nav-bg: #f3e8ff;
}

.omnispec-root[data-mode='dark'] {
--omnispec-bg-primary: #1a1025;
--omnispec-color-primary: #a78bfa;
--omnispec-nav-bg: #2d1b4e;
}

Mapping to Your App's CSS Variables

When integrating with an app that already defines its own design tokens, point the --omnispec-* variables at yours with var() references so the browser resolves them from the host stylesheet at runtime:

.omnispec-root {
--omnispec-color-primary: var(--color-primary);
--omnispec-fg-primary: var(--color-text);
--omnispec-h1-color: var(--h1-font-color, var(--color-heading));
--omnispec-btn-primary-bg: var(--color-primary);
}

Fallback values are supported: var(--btn-font-size, 0.8125rem).

Pro

Passing these same token overrides programmatically through the theme.overrides prop (an arbitrary { '--omnispec-*': value } map on <OmniSpecRenderer>, including per-mode override objects synced via onThemeChange) is a full white-labeling convenience that requires Apiboost OmniSpec Pro. In the free core, apply the identical tokens with the CSS rules shown above — the visual result is the same.

Design Token Reference

Surface Colors

TokenLight DefaultDark DefaultDescription
--omnispec-bg-primary#ffffff#0d1117Main background
--omnispec-bg-secondary#f8f9fa#161b22Cards, panels
--omnispec-bg-tertiary#f1f3f5#21262dTable headers, badges
--omnispec-bg-code#f5f5f5#1c2128Code block background

Text Colors

TokenLight DefaultDark DefaultDescription
--omnispec-fg-primary#1a1a2e#e6edf3Primary text
--omnispec-fg-secondary#4a4a6a#b1bac4Secondary text, descriptions
--omnispec-fg-muted#8c8ca1#7d8590Muted text, hints
--omnispec-fg-code#d63384#ff7b72Inline code text
--omnispec-fg-link#0969da#58a6ffLinks

Headings

TokenLight DefaultDark DefaultDescription
--omnispec-h1-font-size1.75rem1.75remH1 font size (API title)
--omnispec-h1-font-weight800800H1 font weight
--omnispec-h1-color#1a1a2e#e6edf3H1 text color
--omnispec-h2-font-size1.25rem1.25remH2 font size (section headings)
--omnispec-h2-font-weight700700H2 font weight
--omnispec-h2-color#1a1a2e#e6edf3H2 text color
--omnispec-h3-font-size1rem1remH3 font size (sub-section headings)
--omnispec-h3-font-weight600600H3 font weight
--omnispec-h3-color#1a1a2e#e6edf3H3 text color

Brand / Accent

TokenLight DefaultDark DefaultDescription
--omnispec-color-primary#0969da#58a6ffPrimary action color
--omnispec-color-primary-hover#0550ae#79c0ffPrimary hover state
--omnispec-color-primary-text#ffffff#0d1117Text on primary color

Schema styles reuse these tokens. The schemaStyle presentations are fully token-driven — no new tokens are introduced. The tokens style tints the property type with --omnispec-color-primary and the format / enum chips with --omnispec-color-info; the card style draws its nested accent rail from --omnispec-color-primary and its enclosing surface from --omnispec-bg-primary / --omnispec-border-color. Override those tokens to re-skin every schema style at once.

These tokens control the sidebar navigation layout, spacing, and styling. They apply to both spec-derived navigation and custom sidebar navigation.

TokenLight DefaultDark DefaultDescription
--omnispec-nav-bg#f6f8fa#161b22Sidebar background
--omnispec-nav-text#1a1a2e#e6edf3Item text color
--omnispec-nav-hover-bg#eaeef2#21262dItem hover background
--omnispec-nav-accent#0969da#58a6ffActive item border color
--omnispec-nav-active-bg#eaeef2#21262dActive item background
--omnispec-nav-active-border-width0.1875rem0.1875remActive indicator width. Set to 0 to hide
--omnispec-nav-item-padding-v0.625rem0.625remItem vertical padding
--omnispec-nav-item-padding-h0.75rem0.75remItem horizontal padding
--omnispec-nav-indent0.875rem0.875remPer-depth child indentation
--omnispec-nav-item-gap0.5rem0.5remGap between icon, label, and badge
--omnispec-nav-item-radius00Item border radius. Set 0.375rem for rounded items
--omnispec-nav-group-font-size0.8125rem0.8125remGroup heading font size
--omnispec-nav-group-font-weight600600Group heading font weight
--omnispec-nav-group-letter-spacing0.04em0.04emGroup heading letter spacing
--omnispec-nav-group-text-transformuppercaseuppercaseGroup heading text transform. Set to none for sentence case
--omnispec-nav-heading-color#8c8ca1#7d8590Custom-nav section/group heading text color
--omnispec-nav-badge-radius0.25rem0.25remMethod/status badge border radius
--omnispec-nav-badge-text#ffffff#ffffffBadge text color
--omnispec-nav-width18.75rem18.75remSidebar width
--omnispec-nav-divider-color#d0d7de#30363dDivider between custom and spec navigation

Set these tokens on .omnispec-root to get common navigation looks.

Clean — no active border, sentence-case headings, rounded items:

.omnispec-root {
--omnispec-nav-active-border-width: 0;
--omnispec-nav-item-radius: 0.375rem;
--omnispec-nav-group-text-transform: none;
--omnispec-nav-group-font-size: 1rem;
--omnispec-nav-indent: 1.25rem;
}

Compact — narrow sidebar, tighter items, pill-shaped active state:

.omnispec-root {
--omnispec-nav-width: 16rem;
--omnispec-nav-item-padding-v: 0.375rem;
--omnispec-nav-item-radius: 0.25rem;
--omnispec-nav-active-border-width: 0;
--omnispec-nav-active-bg: #eef2ff;
--omnispec-nav-accent: #4f46e5;
}

Minimal — no backgrounds, transparent active state:

.omnispec-root {
--omnispec-nav-bg: transparent;
--omnispec-nav-hover-bg: transparent;
--omnispec-nav-active-bg: transparent;
--omnispec-nav-active-border-width: 0;
}

Scrollbar

Custom scrollbar styling is applied to all scrollable areas inside the renderer (sidebar, main content, code blocks). Both Firefox (scrollbar-width/scrollbar-color) and WebKit (::-webkit-scrollbar) are supported.

TokenLight DefaultDark DefaultDescription
--omnispec-scrollbar-width0.5rem0.5remScrollbar width
--omnispec-scrollbar-tracktransparenttransparentTrack background
--omnispec-scrollbar-thumb#c1c7cd#484f58Thumb color
--omnispec-scrollbar-thumb-hover#a0a8b0#6e7681Thumb hover color

Form controls

Native form controls inside the renderer are themed automatically so they match the active theme (including dark mode) — no per-control configuration needed:

  • Checkboxes & radios are custom-rendered (appearance: none) using --omnispec-input-bg / --omnispec-input-border, and fill with --omnispec-color-primary (white check / centered dot) when selected.
  • Selects use --omnispec-input-bg / --omnispec-input-border / --omnispec-fg-primary for the box, --omnispec-border-radius for the corners, and a custom chevron; hover/focus adopt --omnispec-color-primary.

Override the referenced tokens (--omnispec-color-primary, --omnispec-input-*, --omnispec-border-radius) to re-skin every control at once.

Layout

TokenDefaultDescription
--omnispec-offset-top0pxGlobal offset for sticky elements (sidebar, Try-It panel). Set this to the height of your external sticky header so the renderer clears it.

This is a CSS-only variable — it is not part of the theme.overrides system. Set it via a CSS rule targeting .omnispec-root:

.omnispec-root {
--omnispec-offset-top: 3rem; /* height of your sticky navbar */
}

This single variable adjusts:

  • Sidebar — sticks below the nav, height subtracts the offset
  • Try-It panel — sticky position accounts for the offset
  • Expand/collapse button — clears the nav

Buttons

TokenLight DefaultDark DefaultDescription
--omnispec-btn-font-size0.8125rem0.8125remButton font size
--omnispec-btn-radius0.375rem0.375remButton border radius
--omnispec-btn-primary-bg#0969da#58a6ffPrimary button background
--omnispec-btn-primary-text#ffffff#0d1117Primary button text
--omnispec-btn-primary-bg-hover#0550ae#79c0ffPrimary button hover bg
--omnispec-btn-primary-text-hover#ffffff#0d1117Primary button hover text
--omnispec-btn-primary-shadownonenonePrimary button box-shadow
--omnispec-btn-primary-shadow-hovernonenonePrimary button hover box-shadow
--omnispec-btn-secondary-bg#f8f9fa#21262dSecondary button background
--omnispec-btn-secondary-text#1a1a2e#e6edf3Secondary button text
--omnispec-btn-secondary-bg-hover#eaeef2#30363dSecondary button hover bg
--omnispec-btn-secondary-text-hover#1a1a2e#e6edf3Secondary button hover text
--omnispec-btn-secondary-shadownonenoneSecondary button box-shadow
--omnispec-btn-secondary-shadow-hovernonenoneSecondary button hover box-shadow

HTTP Method Colors

TokenLight DefaultDark DefaultDescription
--omnispec-color-get#1a7f37#3fb950GET method badge
--omnispec-color-post#0550ae#58a6ffPOST method badge
--omnispec-color-put#bf8700#d29922PUT method badge
--omnispec-color-delete#cf222e#f85149DELETE method badge
--omnispec-color-patch#8250df#bc8cffPATCH method badge

AsyncAPI Protocol Colors

TokenLight DefaultDark DefaultDescription
--omnispec-color-publish#0550ae#58a6ffPublish/Send operations
--omnispec-color-subscribe#1a7f37#3fb950Subscribe/Receive operations

Status Colors

TokenLight DefaultDark DefaultDescription
--omnispec-color-success#1a7f37#3fb950Success states, 2xx responses
--omnispec-color-warning#bf8700#d29922Warning states, 4xx responses
--omnispec-color-error#cf222e#f85149Error states, 5xx responses
--omnispec-color-info#0550ae#58a6ffInfo states, 3xx responses

Border & UI

TokenLight DefaultDark DefaultDescription
--omnispec-border-color#d0d7de#30363dBorders, dividers
--omnispec-border-radius0.375rem0.375remBorder radius for cards, inputs
--omnispec-input-bg#ffffff#0d1117Form input background
--omnispec-input-border#d0d7de#30363dForm input border

Typography

TokenLight DefaultDark DefaultDescription
--omnispec-font-sans-apple-system, BlinkMacSystemFont, "Segoe UI", ...SameBody font stack. Override with '"Inter", sans-serif' or any custom font.
--omnispec-font-monoui-monospace, SFMono-Regular, ...SameMonospace font stack
--omnispec-font-size-base0.9375rem0.9375remBase font size
--omnispec-font-size-md1rem1remMedium text (card titles, schema/type section headings)
--omnispec-font-size-sm0.8125rem0.8125remSmall text
--omnispec-font-size-xs0.75rem0.75remExtra small (badges, labels)
--omnispec-font-size-xxs0.625rem0.625remExtra extra small (method badges)
--omnispec-font-size-lg1rem1remLarge text
--omnispec-font-size-xl1.25rem1.25remExtra large text

The default sans-serif stack uses system fonts for zero download cost and instant rendering. To use a custom font like Inter, load the font in your app and set the token with CSS:

<!-- Load Inter via Google Fonts (or self-host) -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
.omnispec-root {
--omnispec-font-sans: "Inter", sans-serif;
}

Programmatic Theme Access

Access the current theme in custom slot components:

import { useTheme } from '@apiboost/omnispec'

function MyCustomComponent() {
const { base, tokens } = useTheme()

return (
<div style={{
backgroundColor: base === 'dark' ? '#1a1a2e' : '#ffffff',
color: tokens['--omnispec-fg-primary'],
}}>
Custom content
</div>
)
}

CSS Override Example

Target the omnispec-root class for global overrides:

.omnispec-root {
--omnispec-font-size-base: 15px;
--omnispec-font-size-sm: 13px;
}

.omnispec-root .omnispec-endpoint-card {
border-radius: 12px;
}

White-Label Checklist

To fully white-label the renderer for a client:

  1. Set --omnispec-color-primary and --omnispec-color-primary-hover to the client's brand color
  2. Set heading colors via --omnispec-h1-color, --omnispec-h2-color, --omnispec-h3-color
  3. Set button styles via --omnispec-btn-* tokens to match the client's button design
  4. Set --omnispec-nav-accent and --omnispec-nav-active-bg to match the primary color
  5. Customize sidebar layout via --omnispec-nav-* tokens (width, padding, indent, radius)
  6. Inject the client's logo via slots.sidebarHeader
  7. Inject the client's header/footer via slots.header / slots.footer
  8. Add custom navigation via sidebarNav
  9. Font families are inherited automatically from the parent app
  • Slots — inject custom components into layout regions
  • Sidebar Navigation — add custom links and groups to the sidebar
  • Configuration — layout modes, Try-It options, callbacks