# Content Recipes

Copy-paste solutions for common content patterns. Each recipe shows the markdown you write and notes on key points.

For deeper explanations, see the [Writing Content](./writing-content.md) guide.

**Note:** These recipes use generic type names (`Hero`, `Features`, `FAQ`, etc.). Your site's template may use different names — check the existing `.md` files in your site to see what types are available, and your template's documentation for details.

---

## Sections

### Hero with Image and CTA Buttons

A bold landing section with headline, description, buttons, and a hero image.

```markdown
---
type: Hero
theme: gradient
---

#> Welcome to
# Acme Corp
## Build something great

We help teams ship products faster with modern tools and beautiful design.

[Get Started](/signup)
[Watch Demo](/demo)

![Hero illustration](./hero.jpg)
```

- The `#>` label line creates a pretitle ("Welcome to") above the title. A smaller heading directly above the title (`### → #`) does the same.
- Standalone links become CTA buttons. The section type decides how they look.
- The image, links, and paragraphs are ingredients — the section type arranges them.

---

### Multi-Line Hero with Accented Text

A bold hero with a two-line headline and the second line styled differently.

```markdown
---
type: Hero
theme: dark
---

#> Our Mission
# Build the future
# [with confidence]{accent}

We help teams ship products faster with modern tools and beautiful design.

[Get Started](/signup)
[Learn More](/about)
```

- Two consecutive `#` headings merge into a multi-line title — one `<h1>` with visual line breaks.
- `[with confidence]{accent}` highlights the second line with accent styling (color + bold).
- The `#>` label line creates a pretitle ("Our Mission") above the title. A smaller heading directly above the title (`### → #`) does the same.

---

### Feature Grid with Icons

A grid of feature cards, each with an icon, title, and description.

```markdown
---
type: Features
---

# Why Choose Us

We've built the tools you need.

### Lightning Fast

![](lu-zap)

Sub-second load times across all devices.

### Bank-Grade Security

![](lu-shield)

Enterprise security with end-to-end encryption.

### Easy Integration

![](lu-plug)

Connect with your existing tools in minutes.

### 24/7 Support

![](lu-headphones)

Real humans ready to help around the clock.

### Analytics Built In

![](lu-bar-chart-3)

Track everything that matters, nothing that doesn't.

### Open Source

![](lu-github)

Transparent, auditable, community-driven.
```

- Each `###` heading starts a new item (card).
- Icons use the `lu-name` format (Lucide). Browse all icons visually at [react-icons.github.io/react-icons](https://react-icons.github.io/react-icons/).

---

### FAQ Section

Expandable questions and answers.

```markdown
---
type: FAQ
---

# Frequently Asked Questions

### How do I get started?

Sign up for a free account and follow our quickstart guide. You'll have your first project running in under five minutes.

### Is there a free plan?

Yes! Our free tier includes unlimited projects and up to 3 team members. No credit card required.

### Can I use my own domain?

Absolutely. Connect any custom domain in your project settings. We handle SSL certificates automatically.

### How do I cancel?

You can cancel anytime from your account settings. No questions asked, no hidden fees.
```

- Each `###` heading becomes a question. The paragraphs below it are the answer.

---

### Pricing Table

Pricing tiers with feature lists.

````markdown
---
type: Pricing
---

# Simple, Transparent Pricing

Choose the plan that's right for you.

### Starter

$9/month

Perfect for individuals and small projects.

- 5 projects
- 1 team member
- Community support
- Basic analytics

[Get Started](/signup?plan=starter)

### Pro

$29/month

For growing teams that need more.

- Unlimited projects
- 10 team members
- Priority support
- Advanced analytics
- Custom domains

[Get Started](/signup?plan=pro)

### Enterprise

Custom

For organizations with advanced needs.

- Everything in Pro
- Unlimited team members
- Dedicated support
- SLA guarantee
- SSO / SAML

[Contact Sales](/contact)

```yaml:pricing
billingToggle: true
annual:
  starter: 7
  pro: 24
  enterprise: null
```
````

- Each `###` heading is a pricing tier with its own paragraphs, lists, and links.
- The YAML data block passes structured data (like billing toggle config) to the section.

---

### Testimonials

Quote cards from customers.

```markdown
---
type: Testimonials
---

# What Our Customers Say

### Jane Smith

> "Absolutely transformed how we build websites. We shipped our redesign in half the time."

CEO at TechCo

![Jane](./jane.jpg)

### Mike Johnson

> "The best developer experience I've found. My team loves working with it."

CTO at StartupX

![Mike](./mike.jpg)

### Sarah Chen

> "Finally, a tool where our content team and engineering team don't step on each other."

VP Engineering at ScaleUp

![Sarah](./sarah.jpg)
```

- Each `###` is a person. Their quote uses blockquote syntax (`>`).
- The paragraph after the quote is their role/company.
- Images become avatars. The order of quote, role, and image within each item doesn't matter.

---

### Team Page

Photo + name + role cards.

```markdown
---
type: Team
---

# Our Team

The people behind the product.

### Sarah Chen

![Sarah](./sarah.jpg)

Lead Engineer

Building systems that scale. Previously at Google and Stripe.

[LinkedIn](https://linkedin.com/in/sarah){target=_blank}

### Alex Rivera

![Alex](./alex.jpg)

Head of Design

Crafting experiences users love. Award-winning designer.

[Portfolio](https://alex.design){target=_blank}

### Jordan Park

![Jordan](./jordan.jpg)

Product Manager

Turning ideas into shipped features. 10 years in SaaS.

[Twitter](https://twitter.com/jordan){target=_blank}
```

- Each `###` is a team member. Provide their image, role, bio, and links — the section type arranges them.

---

### Image Gallery

A set of images displayed in a grid.

```markdown
---
type: Gallery
---

# Project Gallery

![Mountain landscape](./mountain.jpg)
![City skyline](./city.jpg)
![Ocean sunset](./ocean.jpg)
![Forest trail](./forest.jpg)
![Desert dunes](./desert.jpg)
![Lake reflection](./lake.jpg)
```

- Just list your images. The section type handles the gallery layout.
- Alt text is important for accessibility and may be used as captions.

---

### Logo Cloud

A row of partner or client logos.

```markdown
---
type: LogoCloud
---

# Trusted By

![Acme Corp](./logos/acme.svg)
![TechCo](./logos/techco.svg)
![StartupX](./logos/startupx.svg)
![ScaleUp](./logos/scaleup.svg)
![BigCorp](./logos/bigcorp.svg)
```

- Just list your logo images. Use SVG for best quality at any size.

---

### Contact Form

A form section using structured data for field configuration.

````markdown
---
type: Contact
---

# Get in Touch

We'd love to hear from you. Fill out the form below and we'll get back to you within 24 hours.

![](lu-mail)

```yaml:form
fields:
  - name: name
    label: Full Name
    type: text
    required: true
  - name: email
    label: Email Address
    type: email
    required: true
  - name: subject
    label: Subject
    type: select
    options:
      - General Inquiry
      - Technical Support
      - Partnership
  - name: message
    label: Message
    type: textarea
    required: true
submitLabel: Send Message
successMessage: Thanks! We'll be in touch soon.
```
````

- The YAML data block configures the form. The tag name (`form`) and field structure depend on what your template's Contact type expects — check your template's documentation.

---

## Navigation & Layout

### Header with Navigation

Site-wide header. This lives in `layout/header.md`.

```markdown
---
type: Header
---

![Logo](./logo.svg){role=icon}

[Home](/)
[Products](/products)
[Docs](/docs)
[Pricing](/pricing)
[Contact](/contact)
```

- A file in `layout/` makes this appear on every page.
- The icon with `role=icon` becomes the site logo.
- Standalone links become navigation items.

**Auto-navigation alternative**: Some Header types automatically build navigation from your page structure, so you may not need to list links manually. Check the header file that came with your template.

---

### Footer with Link Columns

Site-wide footer. This lives in `layout/footer.md`.

```markdown
---
type: Footer
---

### Product

[Features](/features)
[Pricing](/pricing)
[Changelog](/changelog)
[Roadmap](/roadmap)

### Company

[About](/about)
[Careers](/careers)
[Blog](/blog)
[Press](/press)

### Legal

[Privacy Policy](/privacy)
[Terms of Service](/terms)

---

![](lu-twitter){href="https://twitter.com/example" target=_blank}
![](lu-github){href="https://github.com/example" target=_blank}
![](lu-linkedin){href="https://linkedin.com/company/example" target=_blank}

© 2025 Acme Corp. All rights reserved.
```

- Each `###` heading creates a link column.
- Clickable icons (with `href`) become social media links.
- The final paragraph is the copyright notice.

---

## Pages & Routes

### Adding a New Page

Create a folder under `pages/` and add a `.md` file:

```
pages/
├── home/
├── about/
└── pricing/          ← new page
    └── content.md
```

```markdown
---
type: Pricing
---

# Our Plans

Choose the right plan for you.
```

The page automatically appears at `/pricing` and shows up in navigation. The title defaults to the folder name.

To set a custom title, description, or ordering, add a `page.yml`:

```yaml
title: Pricing
description: Our plans and pricing
order: 3
```

**Tip**: Use `index:` in `site.yml` (not `pages:`) to set your homepage. This way new pages are auto-discovered in navigation without manually updating a list.

---

### Linking Between Pages

Use the `page:` protocol for internal links that won't break if you reorganize:

```markdown
[See our pricing](page:pricing)
[Read the docs](page:docs)
[Contact us](page:about#contact)
```

For simple cases, plain paths work too:

```markdown
[Pricing](/pricing)
```

But `page:` links survive if you move pages to different folders. For pages you link to often, add an `id` in their `page.yml`:

```yaml
# pages/docs/getting-started/installation/page.yml
id: installation
title: Installation Guide
```

Now `[Install guide](page:installation)` works no matter where the page lives.

---

### Blog with an Article List and a Page per Article

Set up a blog: a list of articles, a page for each one, and a few more articles at the bottom of each.

**1. Declare a query** in `site.yml` (or in `queries.yml`):

```yaml
queries:
  articles:
    schema: '@/article'
    sort: date desc
```

**2. Add article files** in `records/article/` — every file there is a record:

```
records/article/
├── hello-world.md
├── new-feature.md
└── tips-and-tricks.md
```

Each article has frontmatter:

```markdown
---
title: Hello World
date: 2025-01-15
description: Our first blog post
---

Welcome to our blog! Here's what we've been building...
```

**3. Create the blog page**, which names the query:

```
pages/blog/
├── page.yml
└── list.md
```

```yaml
# pages/blog/page.yml
title: Blog
query: articles
```

```markdown
<!-- pages/blog/list.md -->
---
type: ArticleList
---

# Blog

The latest from our team.
```

**4. Give each article a page**, with a `[slug]` folder inside the blog:

```
pages/blog/
├── page.yml
├── list.md
└── [slug]/
    ├── article.md
    └── more.md
```

```markdown
<!-- pages/blog/[slug]/article.md -->
---
type: Article
---
```

```markdown
<!-- pages/blog/[slug]/more.md -->
---
type: ArticleList
fetch:
  query: articles
  current: exclude   # every article except the one this page shows
  limit: 3
---

# More from the blog
```

- The `[slug]` folder is a parametric page: one page per article (`/blog/hello-world`). It takes the blog page's `query: articles`, and its `Article` section shows the article the URL names.
- The `more.md` section names the same query, leaves out this page's article, and keeps three.
- These pages don't appear in navigation — they're reached from the list, and from every list of the query: each article carries `$route`, the URL of its page, which list components use for the card's link. See [Linking to a record](../reference/dynamic-routes.md#linking-to-a-record).
- To show the latest three on the home page, add a section there with `fetch: { query: articles, limit: 3 }`.

---

### Adding Search to Your Site

**1. Enable search** in `site.yml`:

```yaml
services:
  search:
    enabled: true
```

**2. Check your template** — most templates include search UI that works automatically once search is enabled.

That's it. The build generates a search index, and the search UI loads it on demand.

**Optional configuration**:

```yaml
services:
  search:
    enabled: true
    exclude:
      routes:
        - /admin
        - /draft
```

See the [Search guide](./search.md) for full configuration options.

---

## Content Patterns

### Hero with Background Image

Any section can have a background image — just add `background:` to the frontmatter. The simplest form is a URL:

```markdown
---
type: Hero
theme: dark
background: /images/hero-bg.jpg
---

# Transform Your Business

Start building with modern tools today.

[Get Started](/signup)
```

For busy images, add an overlay to keep text readable:

```markdown
---
type: Hero
theme: dark
background:
  image:
    src: /images/hero-bg.jpg
    position: center
  overlay:
    enabled: true
    type: dark
    opacity: 0.6
---

# Transform Your Business

Start building with modern tools today.

[Get Started](/signup)
```

- Background images appear behind the content, covering the full section.
- Overlays add a semi-transparent layer so text stays readable. Use `type: dark` or `type: light`.
- Adjust `opacity` (0 to 1) — higher values make the overlay stronger.

---

### Section with Background Color

Any section can use a solid color as its background:

```markdown
---
type: CTA
theme: dark
background: "#1e1e2e"
---

# Ready to Get Started?

Join thousands of teams already using our platform.

[Sign Up Free](/signup)
```

- You can use hex colors (`#1e1e2e`), CSS color names (`navy`), or theme variables (`var(--primary-900)`).
- When using a dark background color, set `theme: dark` so the text colors adapt.

---

### Section with Gradient Background

```markdown
---
type: Hero
theme: dark
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%)
---

# Build Something Beautiful

Modern tools for modern teams.

[Get Started](/signup)
```

- Any CSS gradient works: `linear-gradient(...)`, `radial-gradient(...)`, `conic-gradient(...)`.
- Combine with `theme: dark` for light text on dark gradients.

---

### Hero with Background Video

```markdown
---
type: Hero
theme: dark
background:
  video:
    src: /videos/hero.mp4
    poster: /images/hero-poster.jpg
  overlay:
    enabled: true
    type: dark
    opacity: 0.5
---

# See It in Action

Watch how easy it is to get started.

[Try Free](/signup)
```

- Video backgrounds automatically show a still image for users who prefer reduced motion.
- The poster image shows while the video loads.
- You can also use the simple form: `background: /videos/hero.mp4` (video detected by extension).

---

### Multi-Section Page

A complete page with several sections, each using a different type:

```
pages/home/
├── page.yml
├── 1-hero.md
├── 2-logos.md
├── 3-features.md
├── 4-testimonials.md
├── 5-pricing.md
└── 6-cta.md
```

Each file has its own `type:` in the frontmatter. The number prefix controls the order. You can freely add, remove, or reorder sections by changing the filenames.

---

## Quick Reference

### Content cheat sheet

| What you write | What it becomes |
| --- | --- |
| `# Heading` (first) | Main title |
| `## Heading` (after title) | Subtitle |
| `#> Heading` (a label line) | Pretitle / eyebrow text |
| Paragraphs | Body text |
| `[text](url)` on its own line | Button / CTA |
| `![alt](url)` | Image |
| `![](lu-name)` | Icon |
| `> quote` | Blockquote |
| `- item` | List |
| `### After content` | New item (card, entry) |
| ` ```yaml:tag ` | Structured data |

### Icon family codes

Browse all icons visually at [react-icons.github.io/react-icons](https://react-icons.github.io/react-icons/).

| Code | Library |
| --- | --- |
| `lu` | Lucide |
| `hi` / `hi2` | Heroicons v1 / v2 |
| `fi` | Feather |
| `pi` | Phosphor |
| `tb` | Tabler |
| `bs` | Bootstrap Icons |
| `md` | Material Design |
| `ai` | Ant Design Icons |
| `ri` | Remix Icon |
| `si` | Simple Icons |
| `io5` | Ionicons 5 |
| `bi` | Boxicons |
| `vsc` | VS Code Codicons |
| `wi` | Weather Icons |
| `gi` | Game Icons |
| `fa` / `fa6` | Font Awesome 5 / 6 |

---

## Analytics & Third-Party Scripts

To add Google Analytics, tracking pixels, or any other service that asks you to "paste this code into your site's `<head>`":

1. Create a file called `head.html` in your site folder (next to `site.yml`)
2. Paste the code the service gives you

That's it. The build injects it into every page automatically.

> ⚠️ **This works where your site's pages are built from your files** — `uniweb export`, or `uniweb deploy --host=<adapter>`. If you publish to **Uniweb Cloud** (`uniweb publish`), the host builds your pages from your synced content and `head.html` is **not applied** — your file is kept and synced, but a script in it will not run there.

### ⭐ For a tracking script, there is a shorter way that works everywhere

If the service gave you a single `<script src="…">` line and nothing else — most analytics tools and tag managers do — you can skip `head.html` and name the URL instead:

```yaml
# site.yml
services:
  tracking:
    scripts:
      - https://www.example-analytics.com/tag.js?id=YOUR-ID
```

Same script, same service, same data. The difference is **who loads it**: the site's runtime does, so it works on every host — including Uniweb Cloud, where `head.html` does not apply.

It also gets you two things a pasted snippet does not: it is loaded once per page even as visitors move around your site, and if you add `consent: required` the script is **never fetched at all** until a visitor agrees, rather than loaded and then asked to behave.

**Use `head.html` instead when** the service's snippet has more than a `<script src>` in it — some add a few inline configuration lines, and those have nowhere to go in a URL. See [Tracking](../reference/site-configuration.md#third-party-scripts) for the full reference.

### Google Analytics

```html
<!-- site/head.html -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXXXXX');
</script>
```

Replace `G-XXXXXXXXXX` with your Measurement ID (found in Google Analytics → Admin → Data Streams).

### Multiple scripts

You can put as many scripts as you need in `head.html`. Just paste them one after another:

```html
<!-- Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>/* ... */</script>

<!-- Cookie consent -->
<script src="https://cdn.example.com/consent.js"></script>
```

---

## See Also

- **[Writing Content](./writing-content.md)** — Full guide to writing content
- **[Layout Areas](../reference/layout-areas.md)** — Header, footer, and sidebar details
- **[Linking](./linking.md)** — Stable `page:` links
- **[Records](./collections.md)** — How records work, the `records/` folder and its `folder.yml`, and a page per record
- **[Search](./search.md)** — Search configuration