Skip to content
Domphy

Custom Theme & Slots

Slot system overview

@domphy/press exposes named layout slots — replace any region of the default layout without rebuilding the entire shell:

// press.config.ts
import { defineConfig } from "@domphy/press"
import { CustomLogo, CustomFooter, CustomSidebarHeader } from "./theme"

export default defineConfig({
  themeConfig: {
    slots: {
      logo: CustomLogo,           // replace the site logo
      footer: CustomFooter,       // replace the footer
      sidebarHeader: CustomSidebarHeader,   // insert above sidebar nav
      navBefore: AnnouncementBar, // before the top nav
      contentBefore: EditBanner,  // before every page's content
      contentAfter: PageFeedback, // after every page's content
    },
  },
})

Available slots

SlotLocationDefault
logoTop-left of navSite title text
navBeforeBefore the nav bar
navAfterAfter the nav bar
sidebarHeaderTop of sidebar panel
sidebarFooterBottom of sidebar panel
contentBeforeBefore page content
contentAfterAfter page content
footerBottom of every pageAuto-generated
docAsideRight side TOC panelTOC
notFound404 pageDefault 404

Replace the text logo with an SVG or image:

const CustomLogo = {
  a: [
    {
      img: null,
      src: "/logo.svg",
      alt: "My Docs",
      style: { height: "28px", width: "auto" },
    },
  ],
  href: "/",
  style: { display: "flex", alignItems: "center" },
}

Theme colors

Override the press theme colors to match your brand. The press theme uses Domphy @domphy/theme — set theme variables on :root:

// In press.config.ts — inject CSS into the head
export default defineConfig({
  head: [
    `<style>
      :root {
        /* Override primary color family */
        --primary-hue: 260;    /* purple */
        --primary-chroma: 0.18;

        /* Override neutral warmth */
        --neutral-hue: 240;
        --neutral-chroma: 0.01;
      }
    </style>`,
  ],
})

Or call themeApply() after setTheme() to inject updated CSS variables into the page:

// client/theme-setup.ts
import { setTheme, themeApply } from "@domphy/theme"

setTheme("light", { colors: { primary: [/*...18 lch values...*/], neutral: [/*...18 lch values...*/] } })
themeApply()  // injects updated CSS vars into the document

Custom fonts

Add Google Fonts or self-hosted fonts:

export default defineConfig({
  head: [
    `<link rel="preconnect" href="https://fonts.googleapis.com">`,
    `<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>`,
    `<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Fira+Code&display=swap">`,
    `<style>
      :root {
        --font-sans: 'Inter', system-ui, sans-serif;
        --font-mono: 'Fira Code', monospace;
      }
    </style>`,
  ],
})

Custom CSS

Inject global CSS for the docs site:

export default defineConfig({
  head: [
    `<style>
      /* Wider content area */
      .doc-content { max-width: 900px; }

      /* Custom code block style */
      .shiki { border-radius: 8px; border: 1px solid var(--neutral-3); }

      /* Hide sidebar on print */
      @media print {
        .doc-sidebar { display: none; }
        .doc-content { max-width: 100%; }
      }
    </style>`,
  ],
})
const Footer = {
  footer: [
    {
      div: [
        { span: "© 2025 My Company" },
        { a: "Privacy", href: "/privacy" },
        { a: "Terms", href: "/terms" },
      ],
      style: {
        display: "flex",
        gap: "1rem",
        justifyContent: "center",
        padding: "2rem",
        borderTop: "1px solid var(--neutral-3)",
      },
    },
  ],
}

Page-level slots with frontmatter

Control slots per-page using frontmatter:

---
title: "Getting Started"
layout: home
aside: false
---
// In press.config.ts — react to page-level layout options
export default defineConfig({
  themeConfig: {
    slots: {
      docAside: (context) =>
        context.frontmatter.aside === false ? null : DefaultTOC,
    },
  },
})

context receives:

  • context.frontmatter — the page's frontmatter object
  • context.route — current route path
  • context.sidebar — resolved sidebar for the current route

Announcement bar

Show a dismissible banner at the top of the site:

export default defineConfig({
  themeConfig: {
    announcementBar: {
      id: "v2-release",   // unique — controls dismiss state in localStorage
      content: "🎉 Domphy v2.0 is out! <a href='/blog/v2'>Read the release notes</a>",
      dismissible: true,
    },
  },
})

Extending the layout component

For deeper layout customization, override the layout shell functions exported from @domphy/press:

import { defineConfig, homeShell, pageShell } from "@domphy/press"

// pageShell(context, content) and homeShell(context) are the layout entry points.
// Pass custom overrides via themeConfig slots (see Customization guide).
export default defineConfig({
  themeConfig: {
    // Use slots to inject content into specific regions of the built-in layout.
    // For full layout replacement, provide a custom press theme via pressCSS + custom shell.
  },
})