How to Customize the Open‑SEO UI: A Complete Guide for Developers

Customize the Open‑SEO UI by editing layout primitives in web/src/lib/layout.shared.tsx, extending tailwind.config.ts for styling, and adding file‑based routes under web/src/routes/ to create new pages.

Open‑SEO's front‑end is a modern React application built with TypeScript, Vite, and the Fumadocs UI component library. Understanding how to customize the Open‑SEO UI requires familiarity with its file‑based routing system, reusable layout primitives, and Tailwind‑powered theme system. This guide walks through the core architecture and provides concrete, runnable examples for changing visual styles, adjusting layouts, and adding new pages.

Core Architecture of the Open‑SEO UI

The Open‑SEO UI is organized around five interconnected areas. Each area has specific responsibilities and well‑defined source files.

Area Purpose Key Source Files
Routing File‑based router maps URL paths to React components web/src/router.tsx
Layouts Shared page layouts (home, docs, blog) using Fumadocs UI layouts web/src/lib/layout.shared.tsx
Theme useThemePreference hook manages system, light, or dark modes src/client/components/ThemePreferenceMenuItems.tsx
Main UI Components Reusable pieces including footer, header, and marketing blocks web/src/components/feature-page.tsx, web/src/components/site-footer.tsx
Styling Tailwind CSS configuration for colors, spacing, and utilities tailwind.config.ts

How the Theme System Works

The useThemePreference hook reads and writes a themePreference value to localStorage. It injects an inline script (themePreferenceInitScript) into the HTML head to prevent flash of unstyled content on first paint.

Components consume this value and apply Tailwind dark‑mode classes such as bg-base‑200 and text-base‑content. The theme toggle UI itself lives in src/client/components/ThemePreferenceMenuItems.tsx.

Layout Flow and Shared Options

All pages render inside a layout component. The docs section, for example, uses DocsLayout from Fumadocs UI:

import { DocsLayout } from "fumadocs-ui/layouts/docs";
import { baseOptions } from "@/lib/layout.shared";

export default function DocsPage() {
  return <DocsLayout {...baseOptions}>…</DocsLayout>;
}

The baseOptions object in web/src/lib/layout.shared.tsx is the single source of truth for navigation items, theme toggle visibility, and other global UI behaviors.

How to Customize Visual Styles in Open‑SEO

All UI elements use Tailwind utility classes. Follow these steps to introduce brand colors or adjust spacing.

Step 1: Extend Tailwind Configuration

Open tailwind.config.ts at the repository root and add custom values:

module.exports = {
  darkMode: "class",
  theme: {
    extend: {
      colors: {
        brand: "#0A84FF",
      },
    },
  },
};

Step 2: Apply Custom Classes in Components

Reference the new theme values directly in your components:

<div className="bg-brand text-white p-4 rounded">
  Welcome to the customized Open‑SEO UI!
</div>

Changes hot‑reload instantly when running npm run dev.

How to Override Existing UI Components

Components are imported directly by layouts, so editing the source file propagates changes site‑wide.

Edit web/src/components/site-footer.tsx to update branding:

export function SiteFooter() {
  return (
    <footer className="bg-gray-900 text-gray-100 py-6">
      <p>© 2024 MyCompany – All rights reserved.</p>
    </footer>
  );
}

Restricting Theme Options to Dark Only

Modify src/client/components/ThemePreferenceMenuItems.tsx to remove light and system options:

const THEME_OPTIONS = [
  { value: "dark", label: "Dark", icon: Moon },
];

How to Add New Pages to the Open‑SEO UI

Open‑SEO uses a file‑based routing convention. The router automatically discovers files under web/src/routes/ and maps their paths to URLs.

Creating a Marketing Page

Create a new file following the underscore‑prefix convention for route groups:

// web/src/routes/_marketing/new-feature.tsx
import { FeaturePage } from "@/components/feature-page";

export default function NewFeature() {
  return (
    <FeaturePage
      title="My New Feature"
      description="Explain what it does."
    />
  );
}

This page becomes available at /marketing/new-feature because the file path mirrors the URL hierarchy.

Update web/src/lib/layout.shared.tsx to expose new pages in the site navigation:

export const baseOptions = {
  nav: [
    { title: "Features", href: "/features" },
    { title: "My Custom Page", href: "/marketing/custom-page" },
  ],
};

Complete Customization Examples

Example: Full Custom Marketing Page with Brand Styling

// web/src/routes/_marketing/custom-page.tsx
import { FeaturePage } from "@/components/feature-page";

export default function CustomPage() {
  return (
    <FeaturePage
      title="Custom Page"
      description="A brand‑new marketing page with custom branding."
      primaryCta={{ label: "Get Started", href: "/signup" }}
    />
  );
}

Example: Extended Tailwind with Full Brand Palette

// tailwind.config.ts
module.exports = {
  theme: {
    extend: {
      colors: {
        brand: {
          50: "#E3F2FD",
          500: "#0A84FF",
          900: "#0D47A1",
        },
      },
    },
  },
};

Key Files for Open‑SEO UI Customization

File Role
web/src/router.tsx Central router wiring URL paths to components
web/src/lib/layout.shared.tsx Shared layout options for navigation and theme toggle
src/client/components/ThemePreferenceMenuItems.tsx Theme selection UI
web/src/components/feature-page.tsx Reusable marketing page component
web/src/components/site-footer.tsx Site footer for branding updates
tailwind.config.ts Tailwind CSS configuration

Summary

Frequently Asked Questions

How do I change the default theme in Open‑SEO?

Edit src/client/components/ThemePreferenceMenuItems.tsx and modify the THEME_OPTIONS array. To default to dark mode only, remove the light and system entries. The theme persists via localStorage and applies on first paint through an inline script injected by useThemePreference.

Add navigation links in web/src/lib/layout.shared.tsx within the baseOptions.nav array. Each entry requires a title and href. The router automatically resolves paths relative to your route files in web/src/routes/.

Can I use custom colors throughout the Open‑SEO UI?

Yes. Define custom colors in tailwind.config.ts under theme.extend.colors, then reference them with standard Tailwind utility classes like bg-brand or text-brand-500. The Vite dev server hot‑reloads these changes immediately.

How do I create a completely new page layout in Open‑SEO?

Create a new layout component in web/src/components/ and import it in route files under web/src/routes/. For Fumadocs‑compatible pages, import layout variants from "fumadocs-ui/layouts/docs" or "fumadocs-ui/layouts/home" and pass your custom baseOptions.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →