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 use themeApply in a client script:

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

themeApply(document.documentElement, {
  primary: { hue: 260, chroma: 0.18 },
  neutral: { hue: 240, chroma: 0.01 },
})

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>",
      closeable: true,
    },
  },
})

Extending the layout component

For deeper customization beyond slots — replace the entire layout:

import { createPressLayout } from "@domphy/press/browser"

const CustomLayout = createPressLayout({
  // Override render functions for each layout region
  renderNav: (context) => CustomNav,
  renderSidebar: (context) => CustomSidebar,
  renderContent: (context, content) => ({
    article: [
      CustomContentHeader(context),
      content,
      CustomContentFooter(context),
    ],
  }),
})

export default defineConfig({
  themeConfig: {
    layout: CustomLayout,
  },
})