How to Create a Custom Theme in Hallmark vs Using the Catalog
To create a custom theme in Hallmark, you manually extend the three core data structures—THEMES, ARCHETYPES, and COPY—in site/js/main.js, whereas using the catalog simply means selecting from pre-populated entries in those same structures via the UI picker.
Hallmark’s theming architecture is flexible enough to support both curated catalog themes and完全 bespoke designs. Whether you’re extending the open-source Nutlope/hallmark repository for a brand-specific landing page or experimenting with new component layouts, understanding the difference between catalog consumption and custom theme creation is essential.
Understanding Hallmark's Theming Architecture
Hallmark does not rely on traditional CSS theme switching. Instead, it uses a JavaScript-driven configuration system that swaps entire component archetypes and content based on three centralized data structures defined in site/js/main.js.
The Core Data Structures
The theming system revolves around three immutable-like maps that define every available theme:
THEMES(lines 42-63): Maps theme keys (e.g.,marquee,split) to human-readable display names.ARCHETYPES(lines 70-91): Maps theme keys to specific component templates, such ashero: "marquee"orfooter: "colophon".COPY(lines 35-56): Maps theme keys to text fixtures (eyebrow, lede, quotes) that populate the templates via interpolation.
How the applyTheme() Function Works
When a user selects a theme, the applyTheme(theme) function (lines 53-66) orchestrates the transition:
function applyTheme(theme) {
if (!THEMES[theme]) return;
root.dataset.theme = theme;
swapArchetypes(theme);
setPressed(theme);
localStorage.setItem(STORAGE_KEY, theme);
}
This function validates the theme key, updates the DOM’s data-theme attribute, swaps the component archetypes via swapArchetypes(theme), and persists the choice to localStorage under the key hallmark-theme.
How to Create a Custom Theme in Hallmark
Creating a custom theme requires extending the three data structures with your own key-value pairs. Unlike CSS variable theming, you are configuring which HTML templates get injected and what copy populates them.
Step 1: Register the Theme in THEMES
Add your theme key and display name to the THEMES object in site/js/main.js:
const THEMES = {
// ... existing entries ...
mytheme: "My Custom Theme",
};
This key (mytheme) will be used across all three data structures to identify your configuration.
Step 2: Define Archetypes in ARCHETYPES
Map your theme key to specific component templates in the ARCHETYPES object:
const ARCHETYPES = {
// ... existing entries ...
mytheme: {
hero: "marquee",
footer: "colophon",
navbar: "default"
},
};
You can reuse existing archetype IDs (like marquee or split) or reference new templates you create (see Step 4).
Step 3: Add Copy Content in COPY
Provide text content for interpolation by extending the COPY object:
const COPY = {
// ... existing entries ...
mytheme: {
eyebrow: "Custom Collection",
title: "Build Your Own Theme",
lede: "A bespoke description for my custom Hallmark theme.",
ctaLabel: "Get Started",
quote: "Design is intelligence made visible."
},
};
Missing keys will fall back to default specimen copy during interpolation.
Step 4: (Optional) Create Custom HTML Templates
If the existing templates in site/index.html don’t meet your needs, define a new <template> block:
<!-- In site/index.html -->
<template id="hero-myhero">
<section class="hero hero--myhero">
<span class="eyebrow">{{eyebrow}}</span>
<h1>{{title}}</h1>
<p class="lede">{{lede}}</p>
<button class="cta">{{ctaLabel}}</button>
</section>
</template>
Then reference this new ID in your ARCHETYPES mapping:
mytheme: {
hero: "myhero", // matches template id "hero-myhero"
footer: "colophon"
}
Step 5: Activate and Test
Reload the page. Your custom theme will appear in the theme picker (the dot menu UI) alongside catalog entries. When selected, applyTheme() will automatically persist your choice to localStorage and render your custom configuration.
How to Use the Built-In Catalog
Using the catalog requires zero code modification. The UI provides theme picker dots (data-theme-btn attributes) that call applyTheme() with predefined keys like marquee, editorial, or splash. The shuffle button (.banner__shuffle) randomly selects from existing THEMES entries.
All catalog themes are pre-registered in the three data structures with complete archetype mappings and copy fixtures. To switch themes, simply click the UI controls or use the keyboard shortcuts T (toggle) and R (random).
Key Differences: Custom Theme vs Catalog
| Aspect | Built-In Catalog | Custom Theme |
|---|---|---|
| Setup | Zero configuration; select from UI | Edit site/js/main.js to extend data structures |
| Templates | Uses existing <template id="hero-..."> blocks in site/index.html |
Can reuse existing or create new templates |
| Copy | Pre-defined in COPY object |
Must define custom copy object (optional but recommended) |
| Persistence | Automatic via localStorage (hallmark-theme key) |
Automatic via same mechanism |
| Styling | Defined in site/css/components.css (e.g., .hero--marquee) |
Must add corresponding CSS classes for new archetypes |
Summary
- Hallmark’s theming system is configuration-driven through three core objects in
site/js/main.js:THEMES,ARCHETYPES, andCOPY. - Custom themes require manually extending these objects with new keys, optionally creating new HTML templates in
site/index.html, and ensuring corresponding CSS exists insite/css/components.css. - Catalog themes are pre-populated entries that work immediately via the UI picker without code changes.
- The
applyTheme()function handles all theme switching, archetype swapping viaswapArchetypes(), andlocalStoragepersistence automatically.
Frequently Asked Questions
Can I create a custom theme without editing the core source files?
No, Hallmark currently requires editing site/js/main.js to extend the THEMES, ARCHETYPES, and COPY objects. There is no external JSON configuration loader; the theme registry is hardcoded in the JavaScript source to ensure zero dependencies and prevent CORS issues when running locally.
What happens if I don't provide copy for my custom theme?
If your custom theme key exists in ARCHETYPES but has no corresponding entry in COPY, Hallmark falls back to the specimen copy (default placeholder text). The interpolation engine in swapArchetypes() only replaces keys that exist in your theme’s copy object, leaving other template placeholders empty or using the template’s default innerHTML.
How do I debug a custom theme that isn't rendering?
First, verify your theme key exists in all three data structures—THEMES, ARCHETYPES, and optionally COPY. Check the browser console for early returns in applyTheme() (which occurs if !THEMES[theme]). Next, inspect the DOM to confirm the data-theme attribute on the root element updated. Finally, verify that your template ID matches the archetype reference exactly (e.g., hero-mytheme for ARCHETYPES.mytheme.hero = "mytheme").
Where are the visual styles defined for each theme?
Visual styles are defined in .hero--[archetype] classes within site/css/components.css, not in the JavaScript theme configuration. For example, the marquee hero archetype uses .hero--marquee for its layout and typography. When creating a new archetype, you must add corresponding CSS rules to ensure the component renders correctly.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →