Custom Theme
Ardo's default theme is intentionally not a black box. Nothing is locked down, nothing requires workarounds. You have three levels of customization, and you can mix them freely:
- CSS variables — Change colors, spacing, and typography without touching components
- Component overrides — Replace individual pieces (header, sidebar, footer) with your own React components
- Full custom theme — Build your entire layout from scratch, using Ardo's runtime hooks for data
Start simple. Go deeper when you need to.
CSS Variables
The fastest way to make the theme yours. Override a few CSS custom properties and the entire site updates:
Create a custom CSS file:
/* styles/custom.css */
:root {
--ardo-c-brand: #8b5cf6;
--ardo-c-brand-light: #a78bfa;
--ardo-c-brand-dark: #7c3aed;
}Import it in your app:
import "./styles/custom.css"
import "ardo/ui/styles.css"Available Variables
Here's the full set of variables you can override. You don't need to set all of them — just the ones you want to change:
:root {
/* Brand colors */
--ardo-c-brand: #3b82f6;
--ardo-c-brand-light: #60a5fa;
--ardo-c-brand-dark: #2563eb;
/* Background colors */
--ardo-c-bg: #ffffff;
--ardo-c-bg-soft: #f8fafc;
--ardo-c-bg-mute: #f1f5f9;
/* Text colors */
--ardo-c-text: #1e293b;
--ardo-c-text-light: #475569;
--ardo-c-text-lighter: #64748b;
/* Layout */
--ardo-sidebar-width: 280px;
--ardo-toc-width: 240px;
--ardo-content-max-width: 800px;
--ardo-header-height: 64px;
/* Typography */
--ardo-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", ...;
--ardo-font-mono: ui-monospace, SFMono-Regular, ...;
/* Border radius */
--ardo-radius: 8px;
--ardo-radius-sm: 4px;
}Component Overrides
When CSS isn't enough, replace individual components with your own. Since everything in Ardo is a React component, this works exactly how you'd expect — write a component, use it in your layout:
// components/MyHeader.tsx
import { useConfig, useThemeConfig } from "ardo/runtime"
export function MyHeader() {
const config = useConfig()
const themeConfig = useThemeConfig()
return (
<header className="my-custom-header">
<h1>{config.title}</h1>
{/* Your custom header content */}
</header>
)
}Then use it in your layout. Mix your custom components with Ardo's defaults — replace the pieces you want, keep the rest:
// routes/__root.tsx
import { MyHeader } from "../components/MyHeader"
import { Sidebar, Footer } from "ardo/ui"
export function Layout({ children }) {
return (
<div>
<MyHeader />
<Sidebar />
<main>{children}</main>
<Footer />
</div>
)
}Runtime Hooks
When building custom components, you'll need access to site configuration, sidebar data, and page metadata. Ardo provides React hooks for all of it:
useConfig
import { useConfig } from "ardo/runtime"
function MyComponent() {
const config = useConfig()
return <h1>{config.title}</h1>
}useThemeConfig
import { useThemeConfig } from "ardo/runtime"
function MyNav() {
const themeConfig = useThemeConfig()
return (
<nav>
{themeConfig.nav?.map((item) => (
<a href={item.link}>{item.text}</a>
))}
</nav>
)
}useSidebar
import { useSidebar } from "ardo/runtime"
function MySidebar() {
const sidebar = useSidebar()
// Render sidebar items
}usePageData
import { usePageData } from "ardo/runtime"
function MyContent() {
const pageData = usePageData()
return (
<article>
<h1>{pageData?.title}</h1>
{/* content */}
</article>
)
}useTOC
import { useTOC } from "ardo/runtime"
function MyTOC() {
const toc = useTOC()
return (
<nav>
{toc.map((item) => (
<a href={`#${item.id}`}>{item.text}</a>
))}
</nav>
)
}Full Custom Theme
If you need complete control, you can build your own theme from scratch. Create your components, export them, and use them in your app. Ardo's runtime hooks give you all the data you need — you just decide how to render it:
// theme/index.tsx
export { MyLayout as Layout } from "./Layout"
export { MyHeader as Header } from "./Header"
export { MySidebar as Sidebar } from "./Sidebar"
export { MyTOC as TOC } from "./TOC"
export { MyContent as Content } from "./Content"
export { MyFooter as Footer } from "./Footer"Use your custom theme components in root.tsx and you have a fully custom documentation site — with all of Ardo's content processing, routing, and search still working underneath.