> ## Documentation Index
> Fetch the complete documentation index at: https://docs.joinmarkt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Build a Custom Theme

> End-to-end guide for developers creating Join Markt storefront themes (Vite or Nunjucks).

# Build a Custom Theme

Join Markt themes are **first-class storefronts** — closer to Shopify Liquid themes than to a page builder blob. You own layout, styling, and how products appear. Join Markt owns catalog, cart, checkout, and delivery.

## Choose a runtime

| Runtime            | Stack                              | Best for                                       |
| ------------------ | ---------------------------------- | ---------------------------------------------- |
| **Vite (default)** | React + Tailwind + TypeScript      | New themes, Visual Builder, modern UX          |
| **Nunjucks**       | `.njk` templates + `settings.json` | Imported Liquid/Jinja-style packs, HTML themes |

Both runtimes receive the **same catalog and checkout contracts**. Only the presentation layer differs.

## What you control vs Join Markt

**Theme owns**

* Homepage, product list, product detail, legal pages
* Navbar, footer, hero, product cards
* CSS / design tokens
* How and where products are listed (grids, carousels, featured IDs)

**Platform owns**

* Product data, stock, pricing, variants
* Checkout (`/checkout/{orderId}`)
* Payments, delivery keys, customer portal, tickets
* Public APIs under `/api/stores/by-subdomain/…` and `/api/v1/…`

Never call seller-dashboard session APIs from a public theme.

## Quick start (Vite)

```bash theme={null}
cp -r templates/markt-vite-storefront templates/my-theme
cd templates/my-theme
npm install
npm run dev
```

Required routes in `src/App.tsx`:

* `/` — homepage
* `/products` — catalog
* `/product/:slug` — product detail
* `/privacy`, `/terms`, `/refunds` — policies

Load catalog via `src/lib/storefront-api.ts` (`fetchStorefront`, `useStore`). Render products with your own components — there is no Liquid `{% product %}` tag in Vite; you map data in React.

See [Vite Storefront](/storefront/vite) and [Template Structure](/storefront/template-structure) in the **Themes** tab.

## Quick start (Nunjucks)

Theme ZIP layout:

```text theme={null}
layouts/base.njk
templates/home.njk
snippets/
macros/
assets/
settings.json
```

Homepage / catalog grid — prefer `catalogItems` when the store uses product groups:

```njk theme={null}
{% for item in catalogItems.slice(0, 12) %}
  {% if item.kind == 'group' %}
    <a href="{{ ('/group/' ~ item.group.id) | shopUrl }}">{{ item.group.name }}</a>
  {% else %}
    {% set product = item.product %}
    <a href="{{ ('/product/' ~ product.slug) | shopUrl }}">
      <img src="{{ product.image | imageUrl }}" alt="{{ product.name }}" />
      <h3>{{ product.name }}</h3>
      {% if product.visibility == 'on-hold' %}<span>On hold</span>{% endif %}
      <span>{{ product.minPrice | formatPrice(currency) }}</span>
    </a>
  {% endif %}
{% endfor %}
```

Featured products by ID:

```njk theme={null}
{% set featured = helpers.components.products.getItemsByIds(products, ['slug-or-id-1', 'slug-or-id-2']) %}
{% for product in featured %}
  {# card markup #}
{% endfor %}
```

Reusable blocks:

```njk theme={null}
{% markt_component "navbar" %}
{% markt_snippet "meta-tags.njk" %}
```

Full reference: [Nunjucks Theme API](/storefront/nunjucks), [Products & Catalog](/storefront/products), [Shortcodes & Tags](/storefront/shortcodes), [Policy & Legal Pages](/storefront/policy-pages), [**Nunjucks Theme Pitfalls**](/storefront/nunjucks-pitfalls).

## Homepage checklist

1. Show store name / hero from `store` (or Visual Builder hero settings on Vite).
2. List catalog via `catalogItems` (groups + standalone) — not raw `products` alone.
3. Link product cards to `/product/{slug}`; group cards to `/group/{id}`.
4. Add to cart → platform checkout — never invent your own payment form.
5. Respect `visibility` (`on-hold` = listed, not purchasable) and `stock` (`-1` = unlimited).
6. Wire policy pages from seller Configure — [Policy & Legal Pages](/storefront/policy-pages) (Vite `/privacy`… vs Nunjucks `/privacy-policy`…).

Deep dive: [Homepage & Sections](/storefront/homepage).

## Publish pipeline

1. Seller edits in Visual Builder (Vite) or Code mode / ZIP import (Nunjucks).
2. **Publish** builds artifacts.
3. Live site serves `/markt-theme-assets/live/{revision}/…`.
4. Preview uses a real iframe URL + dist files — **never** flatten React to a static HTML snapshot.

## Next steps

* [Shortcodes & Tags](/storefront/shortcodes)
* [Products & Catalog](/storefront/products)
* [Policy & Legal Pages](/storefront/policy-pages)
* [Nunjucks Theme Pitfalls](/storefront/nunjucks-pitfalls)
* [Homepage & Sections](/storefront/homepage)
* [Theme Builder](/guides/theme-builder)
