Skip to main content

Folders

A theme has a fixed set of folders. Only these are readable and writable by the CLI, the code editor, and the visual editor: Subfolders inside these are not supported. assets/img/logo.png will not sync, keep asset files flat in assets/.

Root files

The four kinds of file

Layout

A layout is the complete HTML document. It receives the rendered template as templateContent and is responsible for the <head>, the global components (navbar, footer, and so on), and the script tags.
layouts/master.njk
The layout used for a page comes from settings.json (templates.<key>.layout), so a theme can ship more than one, but in practice master covers everything.

Template

Templates hold the page body only. Most of them are nothing but the component loop, because the actual content is composed by the merchant in the visual editor:
templates/shop.njk
Both components_order and the component definitions come from settings.json for the current template.

Component

A component is one addable section. The filename must match the component type key in schema.json, so components/hero.njk pairs with a hero entry in schema.components. Components read their own configuration from properties and their instance ID from componentId:
components/text-block.njk
A component does not inherit variables set by whatever rendered it. It receives its own properties, the page data, and the globals. See scope rules.

Snippet

A snippet is a reusable partial that takes keyword arguments. Snippets are not visible in the editor and have no schema entry.
The .njk extension is required in the snippet name. Document a snippet’s arguments in a comment at the top, the way the official themes do:
snippets/section-header.njk

Required files

For a page to render, three things must exist:
  1. An entry for the template key in settings.json under templates, with a layout value.
  2. The layout that entry names, in layouts/.
  3. The template file itself, in templates/.
Missing components and snippets do not break the page. They render the literal text Component not found or Snippet not found in place, which is usually your first clue that a filename and a schema key disagree.

Templates and routes

Routing is not filename-based. SellAuth resolves each URL to a template name, then renders templates/<name>.njk. /terms redirects to /terms-of-service. The current template name is always available as templateName, which is how layouts special-case pages:
The seven legal pages share one route pattern and all render through templates/legal-page.njk, with legal_page telling the template which one it is. See Template Variables for its shape. A legal page without content returns 404, unless a custom page uses that slug.
A theme copy without a legal-page entry in settings.json (every shop copy made before the template shipped, and community themes) keeps rendering terms, privacy and refunds through the older terms, privacy-policy and refund-policy templates, and returns 404 for the four newer pages until the merchant updates the theme. Updating removes the three older templates from the copy. If you maintain a custom theme, add templates/legal-page.njk and its settings.json entry yourself.
Every official layout renders snippets/cookie-consent.njk just before the js.cookie and Alpine script tags, so window.saConsent exists before the theme script and before snippets/script-integrations.njk. The snippet renders nothing unless shop.settings.cookie_consent.enabled is true and the page is not the builder or a preview. Scripts that must wait for consent are written as <script type="text/plain" data-consent="functional|analytics|marketing">; the runtime turns them into live scripts when the category is allowed. The theme script checks window.saConsent.has('marketing') before storing an affiliate code and has('analytics') before storing UTM attribution, and subscribes with onChange so a later acceptance still captures them. Any link to #cookie-settings reopens the preferences. See the Cookie Consent guide for the merchant-facing behaviour.

Custom pages

Merchants can create extra pages with their own slug and their own component composition. All of them render through the single file templates/custom-page.njk. Each custom page gets its own key in settings.json (custom-page-1712345678901) holding its name, slug, layout, and components. At render time:
  • templateName is the settings key, for example custom-page-1712345678901.
  • custom_page holds key, name, and path.
So branch on custom_page.path if a specific page needs special markup:
templates/custom-page.njk
Slugs must match ^[a-z0-9-]+$ and cannot collide with a built-in route. These slugs are reserved:
Custom pages require a qualifying plan. On plans without them, custom page URLs return 404.