Juicer
English

Configuration

site.toml keys juicerlanding reads — top-level chrome keys, the [juicerlanding] palette table, and the nine section blocks that build the home page.

juicerlanding reads its configuration from three places:

  • A small set of top-level site keys (the same ones every juicer theme uses, plus a few landing-specific ones for the topbar / footer).
  • A namespaced [juicerlanding] table for theme-specific palette + sizing overrides.
  • A stack of section blocks ([hero], [[features]], [[pricing]], etc.) that drive the home page. Each block is independently gated; missing block silently omits the section.

The home layout calls nine section partials in a fixed order: hero → trust → features → code → showcase → pricing → testimonials → faq → final-cta. You don’t need to think about the order; you just include the blocks for the sections you want.

Quick example

A minimal site.toml that produces a credible landing page:

title    = "My product"
tagline  = "What it does, in eight words or less."
baseURL  = "https://example.com"
theme    = "juicerlanding"

[hero]
headline    = "The headline."
subheadline = "The subheadline that makes the headline land."
primaryCta   = { label = "Start free", url = "/signup/" }
secondaryCta = { label = "View on GitHub", url = "https://github.com/me/it" }

[[features]]
icon  = "⚡"
title = "Fast"
body  = "Less than a kilobyte."

[[features]]
icon  = "🔒"
title = "Private"
body  = "No cookies, no fingerprinting, no consent banners."

[[features]]
icon  = "💰"
title = "Free"
body  = "Self-hosted is free forever, MIT-licensed."

[finalCta]
title = "Ready to ship?"
body  = "Two minutes to install."
primaryCta = { label = "Start free", url = "/signup/" }

Adding [[pricing]], [[testimonials]], [[faqs]], [showcase], [code], and [[trust]] blocks fills in the rest of the page. The full demo at docs/demos/juicerlanding/ exercises every section — see Demo site.

Top-level keys

Standard juicer keys plus a few landing-specific ones. juicerlanding-specific keys are flagged in the right-most column.

KeyTypeDefaultNotes
titleStringrequiredBrand text in topbar + footer; used as <title> element.
taglineStringunsetAppears under the brand in the footer; appended to <title> when the page title equals the site title.
descriptionStringunsetDefault <meta name="description"> for pages that don’t set their own summary.
authorStringunsetFooter copyright line. Falls back to title.
baseURLStringrequiredStandard juicer key.
themeStringrequiredSet to "juicerlanding".
repoURLStringunsetWhen set, juicerlanding shows a GitHub icon link in the topbar.
faviconStringunsetPath to a favicon; emitted as <link rel="icon"> in <head>.
hideJuicerCreditBooleanfalseSet true to remove the “Built with juicer” line in the footer.
customCSS[String]unsetSite stylesheets loaded after the theme CSS. See Theming → Layer 2.
topbarCtaObjectunset{label, url} — adds a CTA button to the topbar. Surfaced on every page so the conversion path is one click from anywhere.
topnavArrayunsetTopbar nav links: [[topnav]] rows of {label, url}. Note: keyed topnav because top-level nav is reserved by juicer for table-of-contents config.
footerColumnsArrayunsetFooter link columns: [[footerColumns]] rows of {title, links: [{label, url}]}. The brand-blurb column is auto-generated.
trustLabelString"Trusted by teams at"Header line above the trust-bar logos.

Palette + token overrides — [juicerlanding]

All optional. Anything you don’t set keeps the slate / indigo / amber defaults. The full mapping (which token drives which CSS variable) is documented in Theming — juicerlanding follows the same pattern as the other themes.

KeyCSS variableDefaultNotes
brand--brand#4f46e5 (indigo-600)Primary brand colour — primary buttons, focus rings, link hover.
brandStrong--brand-strong#3730a3 (indigo-800)Heading emphasis on light backgrounds; primary-button hover.
brandSoft--brand-soft#eef2ff (indigo-50)Eyebrow chip background, hero gradient, feature-card icon background.
accent--accent#f59e0b (amber-500)Reserved for “warm” highlights; not used by Stage-1 sections.
leaf--leaf#10b981 (emerald-500)Checkmark colour in the pricing + code-section bullet lists.
brandDark--brand (dark)#818cf8 (indigo-400)Lifted indigo for dark-mode backgrounds.
brandStrongDark--brand-strong (dark)#c7d2fe (indigo-200)
brandSoftDark--brand-soft (dark)rgba(129,140,248,0.12)
accentDark--accent (dark)#fbbf24 (amber-400)
leafDark--leaf (dark)#34d399 (emerald-400)
fontSans--font-sansInter stackBody / UI / heading face.
fontMono--font-monoJetBrains Mono stackCode blocks.
measure--measure65chProse column max-width on file.html / folder.html.
gutter--gutter1.5remOuter padding around content blocks.
radiusLg--radius-lg1remLarge border-radius (cards, hero panels, code frame).
logo(none)unsetPath to a small image; rendered next to the brand name in the topbar + footer.

Section blocks

Each section partial reads its own block. Missing block = silently omitted, so an early-stage site can ship with just [hero] + [[features]] + [finalCta], and add the rest later without changing the layout.

[hero] — the main pitch

[hero]
eyebrow      = "v1.0 · privacy-first"
headline     = "The headline."
subheadline  = "Subheadline."
codeLang     = "html"
codeSnippet  = "<script src=...></script>"
screenshot   = "/img/screenshots/hero.png"   # alternative to codeSnippet# alternative to codeSnippet
screenshotAlt = "Dashboard screenshot"

primaryCta   = { label = "Start free", url = "/signup/" }
secondaryCta = { label = "View on GitHub", url = "https://github.com/..." }

codeSnippet and screenshot are mutually exclusive — codeSnippet wins if both are set. If neither is set, the hero renders as a single-column copy block.

[[trust]] — the social-proof strip

trustLabel = "Trusted by teams at"     # optional; default shown# optional; default shown

[[trust]]
logo = "/img/logos/acme.svg"
alt  = "Acme Corp"
url  = "https://acme.example/"          # optional — wraps the logo in <a># optional — wraps the logo in <a>

Logos are rendered greyscale with a hover that lifts the saturation back. Aim for monochrome wordmarks at ~120×40.

[featuresHead] + [[features]] — the feature grid

[featuresHead]
title = "Everything you need, nothing you don't"
body  = "Optional intro paragraph."

[[features]]
icon  = "⚡"            # any emoji, OR a path to an SVG# any emoji, OR a path to an SVG
title = "Title"
body  = "Body copy."

3-up at desktop, 2-up at tablet, 1-up at mobile. The icon is rendered inline; emoji-as-icon is the recommended path because it ships zero asset weight.

[code] — code showcase with bullet list

[code]
title   = "Track what matters"
body    = "Optional intro paragraph above the bullets."
lang    = "javascript"
snippet = "tally('signup', { plan: 'pro' })"
bullets = [
  "First-party only",
  "Properties aggregated server-side",
  "Same API everywhere",
]

Two-column layout — code on one side, copy + checklist on the other.

[showcase] — the screenshot section

[showcase]
title   = "A dashboard you can read at a glance"
body    = "Body copy."
image   = "/img/screenshots/dashboard.svg"
alt     = "Tally dashboard"
caption = "Optional figcaption under the image."
reverse = true     # flip image to the left, copy to the right# flip image to the left, copy to the right

reverse = false (default) puts copy on the left and image on the right. Set true when you’ve already used the same orientation in [code] immediately above and want visual variety.

[pricingHead] + [[pricing]] — pricing tiers

[pricingHead]
title = "Simple pricing"
body  = "Optional intro."

[[pricing]]
tier     = "Free"
price    = "$0"
cadence  = "self-hosted"
tagline  = "One-line subtitle."
features = ["Feature one", "Feature two", "Feature three"]
featured = false
cta      = { label = "Get the source", url = "/docs/install/" }

The row marked featured = true gets the highlighted column treatment (border, glow, scale-up, “Most popular” badge). Order in the file is left-to-right on the page.

[testimonialsHead] + [[testimonials]] — quote cards

[testimonialsHead]
title = "What devs are saying"
body  = "Optional intro."

[[testimonials]]
quote   = "..."
name    = "..."
role    = "..."
company = "..."         # optional# optional
avatar  = "/img/avatars/jane.svg"   # optional# optional

3-up at desktop, 1-up at mobile. The avatar is rendered as a 2.5rem circle; SVG initial-badges work well as placeholders before you have real photos.

[faqHead] + [[faqs]] — accordion

[faqHead]
title = "Frequently asked"
body  = "Optional intro."

[[faqs]]
q    = "Question?"
a    = "Answer."
open = true   # optional — render this item open by default# optional — render this item open by default

Native <details>/<summary>. No JS. The <a> tag inside the answer string works as expected (it’s emitted into the page as plain HTML).

[finalCta] — the close

[finalCta]
title        = "Ready to ship?"
body         = "Two minutes to install."
primaryCta   = { label = "Start free", url = "/signup/" }
secondaryCta = { label = "Read the docs", url = "/docs/" }

Indigo-gradient panel with white copy and a primary + ghost button pair. Always render this if you can — it’s the last conversion surface before the footer.

Per-page frontmatter

Most pages on a juicerlanding site are the home page (layout: home) and a handful of secondary pages (layout: file is the default). The frontmatter knobs:

KeyTypeWhat
layoutStringhome for the section-driven landing page, omitted (or file) for prose pages, folder for section indexes (e.g. /blog/_index.md).
titleStringHeading at the top of the page; also <title>. The home _index.md should omit this so the page title falls through to .site.title.
summaryStringSubtitle under the page title; also <meta name="description"> for that page.
dateDateSort key for folder.html listings. Optional.
langStringSets <html lang> for the page. Defaults to en.

SEO

Every juicer theme ships a shared SEO partial (partials/seo.html) that emits the standard meta block: description (with site-level fallback), canonical link, author meta, robots noindex, OpenGraph + Twitter cards (via the ogTags builtin), Atom feed discovery, and theme-specific JSON-LD. The engine separately writes sitemap.xml and robots.txt.

Site-wide keys

description = "The fastest way to ship docs that look like you wrote them yourself."
ogImage     = "/og/hero.png"

robots   = true
noindex  = false                  # set true for staging/preview domains# set true for staging/preview domains
disallow = ["/private/"]

# Optional: Organization JSON-LD on the homepage. Drives Google's# Optional: Organization JSON-LD on the homepage. Drives Google's
# Knowledge Panel for the brand.# Knowledge Panel for the brand.
[organization]
name   = "Juicer Labs"            # defaults to .site.title when omitted# defaults to .site.title when omitted
logo   = "/img/logo-square.png"
email  = "hello@juicerlabs.io"
sameAs = ["https://github.com/edadma/juicer", "https://twitter.com/juicerlabs"]

Per-page frontmatter

---
title: Pricing
summary: A one-sentence dek for search results and OG cards.
image: /img/og/pricing.png
ogTitle: Snappier headline for socials
ogDescription: Tightened for socials
noindex: true   # excluded from sitemap, JSON-LD suppressed, <meta robots> emitted
---

Structured data emitted

PageSchema
Root sectionWebSite (+ Organization when [organization] is set in site.toml)
Any page with ancestorsBreadcrumbList

Landing-page sites usually don’t have a “post” surface, so juicerlanding doesn’t emit Article JSON-LD by default. Add your own via a <src>/partials/seo-jsonld.html override if you need it.

noindex: true suppresses ALL JSON-LD on that page.

Overriding the SEO partial

Drop a file at <src>/partials/seo.html (or seo-jsonld.html for just the structured-data part). Site overrides win over the theme’s copy.

Search

Esc
to navigate to open Esc to close