Your First Theme
Themes in VeloCMS are npm packages that export React layout components and a theme.manifest.json. VeloCMS loads your BlogLayout and PostLayoutexports and wraps them with the tenant's own navigation chrome. You control the content area — header, footer, post body typography, sidebar presence, everything below the platform nav.
Step 1 — Scaffold
npx create-velocms-theme my-theme
cd my-theme
npm installThe scaffolder asks for a name, slug, type (layout / niche / pack), and an optional niche category (photographer, restaurant, etc.). It creates src/BlogIndex.tsx, src/PostLayout.tsx, a theme.manifest.json, and a Tailwind preset override file.
Step 2 — Define your color tokens
Open src/styles.css and set your custom properties. VeloCMS theme tokens use OKLCH for perceptual uniformity — pick a primary hue and derive variants from it rather than hard-coding hex values.
:root {
--theme-font-heading: "Playfair Display", Georgia, serif;
--theme-font-body: "Inter", system-ui, sans-serif;
--theme-color-bg: oklch(99% 0.002 100);
--theme-color-text: oklch(15% 0.01 100);
--theme-color-accent: oklch(55% 0.22 30); /* warm red */
--theme-color-muted: oklch(95% 0.005 100);
}Step 3 — Build the BlogIndex component
Your BlogIndex receives posts, settings, and tenant as props. VeloCMS injects them at render time. Keep the markup semantic — one <h1> for the blog name, <article> per post preview, <time datetime="...">on dates. The platform monitors Core Web Vitals and themes that break LCP < 1000ms get flagged in the marketplace.
Step 4 — Build the PostLayout component
PostLayout receives a post object and a pre-rendered content HTML string. Style the prose area — font size, line height, heading levels, blockquotes, code blocks. Avoid !important overrides; the platform injects a CSS reset that your styles should layer on top of gracefully.
Step 5 — Update the manifest
Check that theme.manifest.json matches your package.json name and exports the correct component paths. The exports.components map tells VeloCMS which file to load for each slot.
{
"$schema": "https://velocms.org/schemas/theme-v1.json",
"name": "velocms-theme-my-theme",
"displayName": "My Theme",
"version": "1.0.0",
"type": "layout",
"exports": {
"components": {
"BlogLayout": "./dist/BlogIndex.js",
"PostLayout": "./dist/PostLayout.js"
}
},
"pricing": { "model": "free" }
}Step 6 — Build and submit
npm run build
velocms build # produces velocms-theme-my-theme-1.0.0.tgz
velocms publish # submits as draftTheme review checks visual correctness in a sandbox tenant across three screen sizes (mobile 375px, tablet 768px, desktop 1440px). Include a preview/thumbnail.png (400×300) and at least one full-page screenshot in preview/screenshot-1.png. Submissions without screenshots are soft-rejected automatically.
What makes a great theme
Lighthouse score above 95, WCAG AA contrast on all text, semantic HTML, and something that looks different from the built-in presets. The marketplace is already well-stocked with minimal-dark and editorial-serif options — a photography portfolio theme or a restaurant menu theme with strong visual identity has a much better conversion rate. Niche beats generic.