Themes Overview

A theme in Headcode CMS defines how your website looks and how its content sections are structured.

Each theme contains reusable sections — components such as Hero, Header, Footer, Features, RichText, Image, Image Gallery, or CodeSnippets.

1. Where Themes Are Installed

When you install a theme, it’s added to: components/headcode/themes/<theme-name>

For example, the Vienna theme (included in the starter kit) is installed at: components/headcode/themes/vienna

Each theme can include multiple sections that can be mixed and matched in your website’s configuration.

2. Using a Theme in Your Project

To enable a theme, register its sections in your headcode.config.ts file.

Here’s an example configuration using sections from a theme:

headcode.config.ts
export const headcodeConfig: HeadcodeConfig = {  version: 'v01',  entries: [    {      namespace: 'global',      key: 'home',      sections: [        { section: heroSection },        { section: featuresSection },        { section: textSection },        { section: imageSection },      ],    },    // Other entries...  ],};

This defines the homepage (namespace: "global", key: "home") and lists the sections that make it up.

3. Rendering Sections

To render the content for an entry, use the Headcode CMS utilities found in lib/headcode/index.ts.

These functions load and parse entry data, allowing you to render the corresponding section components.

page.tsx
export default function Home() {  return <HomeSection />;}async function HomeSection() {  'use cache';  const sections = await getSections('global', 'home');  return sections.map((section) => (    <div key={section.id}>      {section.name === 'hero' && <Hero sectionData={section.data} />}      {section.name === 'features' && <Features sectionData={section.data} />}      {section.name === 'text' && <Text sectionData={section.data} />}      {section.name === 'image' && <SingleImage sectionData={section.data} />}    </div>  ));}

Each section.name corresponds to the name property in the section definition (e.g., "hero", "text", etc.).

4. Using Default Section Data

During development, you may not have real CMS data yet.

You can provide default section data to render a complete layout even when no entries exist in the database.

Here’s an example setup with fallback data:

page.tsx
export default function Home() {  return <HomeSection />;}async function HomeSection() {  'use cache';  const sections = await getSections('global', 'home');  if (sections.length === 0) {    return (      <div>        <Hero sectionData={defaultHero} />        <Text sectionData={defaultText} />      </div>    );  }  return sections.map((section) => (    <div key={section.id}>      {section.name === 'hero' && <Hero sectionData={section.data} />}      {section.name === 'features' && <Features sectionData={section.data} />}      {section.name === 'text' && <Text sectionData={section.data} />}      {section.name === 'image' && <SingleImage sectionData={section.data} />}    </div>  ));}const defaultHero: HeroData = {  title: 'A Minimalistic Web CMS',  subtitle: 'Published as a shadcn repository',};const defaultText: TextData = {  text: {    type: 'doc',    content: [      {        type: 'paragraph',        content: [{ type: 'text', text: 'Lorem ipsum dolor sit amet...' }],      },    ],  },};

5. Sections Without Rendering Components

Not every section needs to render something on the page. You can also create meta sections, sections that store structured data such as metadata, SEO information, author details, or campaign settings.

Meta sections usually define fields but don’t include a React component. They’re useful for storing non-visual information that can be accessed programmatically when rendering or processing content.

These sections are often pinned in your headcode.config.ts, ensuring they can’t be removed from an entry.