Site UI Configuration
Configure ArdoRoot, header, footer, edit links, last-updated metadata, and JSX sidebar sections from root.tsx.
Build-time options belong in ardo() config. Site chrome belongs in React. Define the header, left
rail, sidebar panels, footer, edit links, and last-updated metadata in your app's root.tsx.
Minimal Root
Every Ardo app needs the generated config. Navigation is composed with React components.
import {
ArdoGeneratedSidebar,
ArdoHeader,
ArdoNav,
ArdoNavLink,
ArdoRoot,
ArdoRootLayout,
ArdoSidebar,
ArdoSidebarSection,
} from "ardo/ui"
import config from "virtual:ardo/config"
import "ardo/ui/styles.css"
export function Layout({ children }: { children: React.ReactNode }) {
return <ArdoRootLayout>{children}</ArdoRootLayout>
}
export default function Root() {
return (
<ArdoRoot config={config}>
<ArdoHeader>
<ArdoNav>
<ArdoNavLink to="/guide/getting-started">Guide</ArdoNavLink>
</ArdoNav>
</ArdoHeader>
<ArdoSidebar>
<ArdoSidebarSection id="guide" label="Guide" to="/guide/getting-started">
<ArdoGeneratedSidebar section="guide" />
</ArdoSidebarSection>
</ArdoSidebar>
</ArdoRoot>
)
}ArdoRootLayout owns the document-level theme bootstrap. ArdoRoot owns the React Router outlet,
Ardo providers, and the shell slots supplied as JSX children.
RootLayout Theme Policy
By default, ArdoRootLayout uses theme="auto": it applies a stored ardo-theme preference first
and falls back to prefers-color-scheme. Set an explicit theme policy when a site should not be
user-selectable:
export function Layout({ children }: { children: React.ReactNode }) {
return <ArdoRootLayout theme="light">{children}</ArdoRootLayout>
}| Theme policy | Behavior |
|---|---|
auto | Stored user preference wins; system preference is the fallback. Default. |
light | Always render light mode and clear stale stored theme preferences. |
dark | Always render dark mode and clear stale theme preferences. |
system | Always follow prefers-color-scheme and clear stored preferences. |
ArdoRoot
ArdoRoot accepts site-wide content settings as props and shell components as children.
| Prop | Type | Purpose |
|---|---|---|
config | ArdoConfig | Generated site config from virtual:ardo/config. |
editLink | { pattern: string; text?: string } | Site-wide edit-link pattern for Markdown pages. |
lastUpdated | { enabled?: boolean; text?: string; formatOptions?: Intl.DateTimeFormatOptions } | Site-wide last-updated display settings. |
labels | ArdoLabelsInput | Override default UI chrome strings. |
tocLabel | string | Label for the table-of-contents panel. |
className | string | Replace the default layout class. |
children | ReactNode | ArdoHeader, ArdoSidebar, ArdoFooter, and optional content overrides. |
Header
Use ArdoHeader for the default responsive header. Put ArdoNav links directly inside it. Use
ArdoHeaderActions for right-side actions.
import { ArdoHeader, ArdoHeaderActions, ArdoNav, ArdoNavLink, ArdoSocialLink } from "ardo/ui"
import logo from "./assets/logo.svg"
;<ArdoHeader logo={logo} title="My Docs" searchPlaceholder="Search documentation...">
<ArdoNav>
<ArdoNavLink to="/guide/getting-started">Guide</ArdoNavLink>
<ArdoNavLink to="/api-reference">API</ArdoNavLink>
</ArdoNav>
<ArdoHeaderActions>
<ArdoSocialLink href="https://github.com/example/project" icon="github" />
</ArdoHeaderActions>
</ArdoHeader>If brand.logo is configured in ardo(), ArdoRoot passes it to the default header unless the
header sets its own logo.
| Header prop | Purpose |
|---|---|
logo | String URL or { light, dark } logo variants. |
title | Header title. Defaults to config.title. |
search | Set to false to hide search. Defaults to true. |
searchPlaceholder | Placeholder for the search input. |
themeToggle | Set to false to hide the theme toggle. Defaults to true. |
className | Replace the default header class. |
Sidebar Sections
The left navigation is always a rail plus a panel. Define both with ArdoSidebarSection: the section
props create the rail item, and the section children create the panel.
import { ArdoGeneratedSidebar, ArdoSidebar, ArdoSidebarSection } from "ardo/ui"
import { BookOpen, Code2 } from "lucide-react"
;<ArdoSidebar>
<ArdoSidebarSection
id="guide"
label="Guide"
to="/guide/getting-started"
icon={<BookOpen size={18} />}
>
<ArdoGeneratedSidebar section="guide" />
</ArdoSidebarSection>
<ArdoSidebarSection id="api-reference" label="API" to="/api-reference" icon={<Code2 size={18} />}>
<ArdoGeneratedSidebar section="api-reference" />
</ArdoSidebarSection>
</ArdoSidebar>ArdoGeneratedSidebar renders the Markdown and TypeDoc navigation generated from route files for the
given top-level section. For fully manual navigation, compose links and groups directly:
<ArdoSidebarSection id="guide" label="Guide" to="/guide/getting-started">
<ArdoSidebarGroup title="Guide">
<ArdoSidebarLink to="/guide/getting-started">Getting Started</ArdoSidebarLink>
<ArdoSidebarLink to="/guide/configuration">Configuration</ArdoSidebarLink>
</ArdoSidebarGroup>
</ArdoSidebarSection>Footer
Pass ArdoFooter as a child of ArdoRoot.
<ArdoFooter
sponsor={{ text: "Example Co", link: "https://example.com" }}
message="Released under the MIT License."
copyright="Copyright 2026 Example Co"
/>Edit Links and Last Updated
editLink and lastUpdated are site-wide content settings. Ardo applies them to Markdown and MDX
document pages, and page frontmatter can opt out with editLink: false or lastUpdated: false.
<ArdoRoot
config={config}
editLink={{
pattern: "https://github.com/example/project/edit/main/docs/app/routes/:path",
text: "Edit this page on GitHub",
}}
lastUpdated={{
enabled: true,
text: "Last updated",
formatOptions: { dateStyle: "medium" },
}}
tocLabel="On this page"
>
{/* Header, sidebar, and footer here */}
</ArdoRoot>The :path placeholder receives the route file path relative to the generated Markdown route root.
Route-Level Chrome
For route-level chrome suppression, export a handle from the route:
export const handle = { layout: "bare", chrome: false }chrome: false removes header and footer for that route. layout: "bare" removes sidebar and rail
rendering.