Build Your Own Theme
You can create your own theme for your website project, either for personal use or to share it privately or publicly with others.
Each theme consists of a set of sections that define content structure and presentation.
You can place these sections anywhere in your project, but if you plan to publish the theme, it’s best to organize it under: components/headcode/themes/<theme-name>
1. Creating a Section
Each section defines how a part of your page looks and what data can be edited in the Headcode Admin.
Here’s a simple example of a hero section:
export const heroSection = { name: 'hero', label: 'Hero Section', fields: { title: TextField({ label: 'Title', }), subtitle: TextareaField({ label: 'Subtitle', }), primaryButton: LinkField({ label: 'Primary Button', }), } satisfies Fields,}export type HeroData = InferSectionData<typeof heroSection.fields>export function Hero({ sectionData }: { sectionData: unknown }) { const { data } = parseSectionData(heroSection.fields, sectionData) return ( <div> <h1>{data.title}</h1> <p>{data.subtitle}</p> <Button href={data.primaryButton.url}> {data.primaryButton.title} </Button> </div> )}First you create a section definition (heroSection):
The name uniquely identifies the section.
The label is shown in the admin UI.
The fields define editable data (Form fields rendered in Headcode Admin).
You can use any available field type (TextField, TextareaField, LinkField, etc.) or create your own custom ones.
Then infer the TypeScript data type for your section using InferSectionData. This gives you full type safety when rendering the section.
export type HeroData = InferSectionData<typeof heroSection.fields>;
Next, create a React component that renders the section on your page:
export function Hero({ sectionData }: { sectionData: unknown }) { const { data } = parseSectionData(heroSection.fields, sectionData) return ( <div> <h1>{data.title}</h1> <p>{data.subtitle}</p> <Button href={data.primaryButton.url}> {data.primaryButton.title} </Button> </div> )}How It Works
parseSectionData validates and parses the incoming sectionData object.
The resulting data object is fully typed as HeroData, giving you autocompletion and type hints in your component.
Use this data object to render your section contents.
3. Publishing Your Theme
Once your theme works locally, you can publish it so others can install it directly from your registry, just like a shadcn/ui component. Follow the official Shadcn Registry guide:
https://ui.shadcn.com/docs/registry
There you’ll learn how to create a registry entry for your theme and publish it privately or publicly.
Your Own Theme Store
If you’re building multiple themes or want to share them with your team or clients, you can create your own theme store by hosting your own shadcn registry.