Skip to content

AI Agent Built Themes

Baan supports a second type of theme where you instruct an AI coding agent — Claude Code, Cursor, or Codex — to write TSX components directly. This unlocks any layout or interaction that React can express.


Admin GeneratedAI Agent Built
HowAdmin UI promptAI agent writes TSX
Structureconfig.json + CSS onlyFull TSX component set
FlexibilityPreset variants + colorsUnlimited
Best forColor/variant changesCustom layouts, widgets, unique interactions

Use AI Agent Built when you need something outside the available presets — a reading progress sidebar, a docs-style tree navigation, a magazine layout with custom card logic, or anything with unique interactivity.


The simplest prompt works — the agent reads the theme documentation and builds the scaffolding automatically.

Create a theme called "ocean". Ocean-like atmosphere.
Create a theme called "startup". Modern SaaS landing page style blog.
Create a theme called "tech-journal".
- Single column, no sidebar
- Compact left-aligned header
- Article list as text-only (no images)
- Monospace font
- Dark background with green accent
Create a theme called "midnight".
Color palette:
- Background: #0f172a (dark navy)
- Text: #e2e8f0 (light gray)
- Accent: #7c3aed (purple)
Cards with large border radius (rounded-xl), shadow intensifies on hover.
Tags displayed as hashtags (#React style).

Level 4: Customize based on an existing theme

Section titled “Level 4: Customize based on an existing theme”
Create a "docs-site" theme based on the the-publish theme.
- Keep the left tree navigation
- Add table of contents in the right sidebar
- More neutral (gray-based) color scheme
Create a theme called "monograph".
- Ultra-thin fixed header (44px), site name only
- Minimal black & white design
- Right sidebar on article pages with a reading progress tracker
(auto-extracts h2/h3 for ToC, highlights current section on scroll)
Note: avoid naming a theme `prose` — it collides with Tailwind's
`@tailwindcss/typography` utility class.

The agent creates a directory under themes/my-theme/:

themes/my-theme/
├── theme.json ← theme metadata (includes `ai` field)
├── config.ts ← pagination colors (required — build fails without it)
├── prompts/ ← Theme Provenance (required)
│ ├── concept.md ← design concept & principles (English)
│ └── generation.md ← optional: the generation prompt
├── styles/theme.css ← CSS variables
├── components/
│ ├── layout/
│ │ ├── Layout.tsx ← main layout wrapper
│ │ ├── SiteHeader.tsx
│ │ └── SiteFooter.tsx
│ └── post/
│ ├── PostCard.tsx ← article card
│ ├── PostContent.tsx ← article body
│ └── RelatedPosts.tsx
└── templates/
└── home-template.tsx ← home page template

The theme is auto-detected at build time — no manual registration or file edits outside the theme directory are needed. Any directory under themes/ with a theme.json is picked up automatically.

Every theme must bundle its design prompts. theme.json records the generation context, and prompts/concept.md documents the design intent in English:

{
"ai": {
"agent": "Claude Code",
"skills": ["create-theme"],
"generatedAt": "2026-04-18"
}
}

The skills array can include built-in skill names (e.g. "create-theme") and references to custom skill files bundled at prompts/skills/<name>.md. Both forms can coexist.

This is what sets Baan apart from traditional theme systems: consumers receive the theme’s recipe (prompts) alongside the compiled code. They can read the intent, fork by editing the prompt, or feed it to a different AI agent. See Creating Themes → Theme Provenance for the full specification.


Themes define their color palette as CSS variables in styles/theme.css. Variables use HSL space-separated format — no hsl() wrapper.

:root {
--background: 0 0% 100%;
--foreground: 0 0% 7%;
--card: 0 0% 100%;
--primary: 0 0% 7%;
--primary-foreground: 0 0% 98%;
--muted: 0 0% 96%;
--muted-foreground: 0 0% 42%;
--accent: 0 0% 94%;
--border: 0 0% 90%;
--radius: 0.25rem;
}

Use Tailwind classes that reference these variables — avoid hardcoded colors like bg-white or text-gray-900:

bg-background, text-foreground ← page background and body text
bg-card, text-card-foreground ← cards
bg-muted, text-muted-foreground ← subtle elements
bg-primary, text-primary-foreground ← primary accent
border-border ← borders

Every theme must have a config.ts — the build fails without it:

export const themeConfig = {
pagination: {
activeColor: "#111111",
hoverColor: "#f5f5f5",
},
};
export type ThemeConfig = typeof themeConfig;

In Next.js App Router, the Layout component stays mounted across page navigations. A useEffect with an empty dependency array only runs once, so DOM-dependent logic (like a table of contents) becomes stale after navigating.

Fix: use usePathname() as a dependency:

import { usePathname } from "next/navigation";
const pathname = usePathname();
useEffect(() => {
setItems([]);
const raf = requestAnimationFrame(() => {
// new DOM is available after one frame
const article = document.querySelector("article");
// ... DOM scan
});
return () => cancelAnimationFrame(raf);
}, [pathname]); // re-runs on every route change

The Admin Customizer preview panel takes ~350px of screen width. At 1440px, the preview iframe is ~1090px — below the xl breakpoint (1280px) but above lg (1024px). Using xl: makes sidebars invisible in the preview.

// Avoid: invisible in Customizer preview
<aside className="hidden xl:block">
// Use instead
<aside className="hidden lg:block">

To keep navigation links visually aligned with the content below, use the same CSS grid template in both the header and the main layout:

// Same grid in both Layout.tsx and SiteHeader.tsx
<div className="grid grid-cols-1 lg:grid-cols-[1fr_640px_200px] gap-0 lg:gap-8">

When navStyle is passed to HeaderNavigation, each link gets px-3, offsetting the first item. Fix with [&_a]:pl-0:

<HeaderNavigation
className="flex items-center gap-6 text-sm [&_a]:pl-0"
navStyle={navigationStyle}
/>

Use an existing fontKey in theme.json — no code changes required:

fontKeyFont
interInter (sans-serif)
merriweatherMerriweather (serif)
jetbrains-monoJetBrains Mono (monospace)

Terminal window
npm run build # must pass before finishing

Select the theme name in Admin → Settings → Theme to apply it immediately.