Customization
How to change colors, fonts, copy, layout, and branding — without breaking the design system.
The customization order
When you fork Zutra, change things in this order:
src/config/site.ts— name, tagline, URL, social handlessrc/config/features.ts— what shows on the features sectionsrc/config/pricing.ts— your plan tiers and copysrc/config/hero.ts— hero copy, simulator metricssrc/config/nav.ts— top nav linkssrc/styles/global.css— colors, fonts, radii (only if needed)- Components — last resort, only for layout-level changes
Most customisations need only steps 1–5.
Site identity
src/config/site.ts:
export const SITE = {
name: 'Your SaaS',
tagline: 'The tagline that sells.',
description: 'Longer description for SEO meta tags.',
url: SITE_URL, // edit in src/site.ts
appUrl: 'https://app.yourdomain.com',
twitterHandle: '@yourhandle',
ogImage: '/og/home.svg',
themeColor: '#000000',
};
SITE_URL comes from src/site.ts — it’s also pulled into astro.config.mjs for sitemap and OG generation.
Logo
The Logo component (src/components/Logo.astro) supports three modes:
export const LOGO = {
type: 'icon+text', // 'icon+text' | 'image' | 'text'
iconSrc: '/logo-icon.svg',
imageSrc: '/logo.svg',
imageAlt: SITE.name,
};
icon+text— small mark + name (default)image— full wordmark image, replaces everythingtext— name only, no icon
Replace public/logo.svg and public/logo-icon.svg with your brand assets. Keep them under 5KB for fast LCP.
Hero copy
src/config/hero.ts:
export const HERO = {
badge: 'Early Access',
headline: '...', // actually comes from i18n (translatable)
subline: 'Ship production-grade SaaS in days — not months.',
socialProof: {
label: 'Trusted by engineers at',
companies: ['Vercel', 'Linear', 'Stripe', 'Railway'],
},
};
The headline itself is pulled from src/i18n/en/hero.json (hero.headline) — this is what makes it translatable. Update both en/hero.json and es/hero.json.
The simulator window (the mock UI on the right of the hero) reads from HERO.simulator.metrics, .logs, .deploySteps, and .team. Edit those to match your actual product story.
Pricing
src/config/pricing.ts — see the Configuration Reference for the full shape. Common edits:
- Add a plan — append to the
PRICINGarray - Change a price — update
monthlyPrice/annualPrice - Change a feature — edit the
featuresarray (each item hastextandincluded: boolean) - Highlight a plan — set
highlighted: true(only one at a time)
The pricing UI (PricingCard.astro) reads from this config and renders everything — there’s nothing to edit in the component.
Nav
src/config/nav.ts:
export const NAV = {
links: [
{ href: '/features', label: 'Features' },
{ href: '/pricing', label: 'Pricing' },
{ href: '/docs', label: 'Docs' },
{ href: '/changelog', label: 'Changelog' },
{ href: '/customers', label: 'Customers' },
{ href: '/blog', label: 'Blog' },
],
dropdown: [
{ href: '/dashboard', label: 'Dashboard' },
{ href: '/about', label: 'About' },
// ...
],
cta: {
label: 'Get the template',
href: 'https://your-purchase-link.com',
},
};
The dropdown appears as “Pages ▾” in the desktop nav. To hide it before launch, set FEATURE_FLAGS.demoDropdown: false in src/config/features.ts.
Colors
For most projects, you don’t need to touch the colors — pick an accent via the ThemePicker. But if you want a single brand color baked in:
- Set
FEATURE_FLAGS.themePicker: falseinsrc/config/features.ts - Edit the
:rootblock at the top ofsrc/styles/global.css:
:root {
--accent: #your-brand-color;
--accent-hover: #lighter-shade;
--accent-fg: #ffffff; /* foreground color on accent backgrounds */
}
For more invasive changes (full rebrand), edit the @theme block:
@theme {
--color-void: #000000;
--color-deep: #your-deep;
--color-surface: #your-surface;
--color-elevated: #your-elevated;
--color-text-primary: #your-text;
/* ... */
}
Fonts
src/styles/global.css imports fonts via @fontsource:
@import "@fontsource/inter/400.css";
@import "@fontsource/inter/500.css";
@import "@fontsource/inter/600.css";
@import "@fontsource/inter/700.css";
To switch to a different family:
pnpm add @fontsource/your-font
Then edit global.css and the --font-family-sans token in @theme.
Monospace uses "Berkeley Mono", with "JetBrains Mono" and "Fira Code" as fallbacks. To swap, edit --font-family-mono in @theme.
Layout changes
If you need to change the layout of an existing section — for example, switching the features grid from 3 columns to 4 — open the component (src/components/home/FeaturesSection.astro) and edit the grid classes.
If you need to add a new section to a page:
- Create a new component under the relevant feature directory (
src/components/home/) - Import it in the page (
src/pages/index.astro) - Place it in the right vertical order
If you need to remove a section, delete the import + usage in the page file. Don’t delete the component itself unless you’re sure no other page uses it.
Animations & micro-interactions
The template uses three sources of motion:
- Tailwind transitions —
transition-colors duration-150,hover:bg-..., etc. <style>blocks — for keyframes (.fadeIn,.pulse-ring)- CSS view transitions — Astro’s built-in page-transition system
If you disable animations globally (for accessibility), the @media (prefers-reduced-motion: reduce) block at the bottom of global.css already does this.
Next steps
- Theming — how the ThemePicker works, adding new accents
- Configuration Reference — every
src/config/*.tsfield - Components — the UI primitives and how to extend them