Basker Docs

Layouts

Basker's layout system wraps every template with shared HTML (head, navigation, footer)

A layout is the HTML shell that wraps every template: <html>, <head>, <body>, header, footer. It is where the document structure, global navigation, asset loading, and head injections live.

Start with a theme that follows the required directory structure.

Steps

1. Create the default layout file

Every theme must include layouts/default.liquid. Unless a template specifies a different layout, this layout wraps all templates.

layouts/default.liquid

If this file is missing, theme validation fails with an error.

2. Add the HTML document skeleton

The layout contains the full HTML document. Use {{ content_for_layout }} to mark where the rendered template output is injected.

<!DOCTYPE html>
<html lang="{{ locale }}">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>{{ page.title | default: tenant.name }}</title>

  {{ content_for_header }}

  {{ 'main.css' | asset_url | stylesheet_tag }}
</head>
<body class="{{ body_classes }}">

  {% render 'site-header' %}

  <main id="main-content" role="main">
    {{ content_for_layout }}
  </main>

  {% render 'site-footer' %}

  {{ 'main.js' | asset_url | script_tag }}
</body>
</html>

{{ content_for_layout }} is required. Without it, the rendered template has nowhere to appear.

3. Inject head content with content_for_header

{{ content_for_header }} outputs system-injected content for the <head>:

  • Preconnect hints for CDN domains.
  • Generator meta tag.
  • Preview-mode scripts and styles when active.
  • reCAPTCHA scripts when forms use reCAPTCHA.

Place it after your own meta tags and before your stylesheets.

4. Load assets with asset_url and tag filters

Use asset_url to reference files in assets/. Pair it with stylesheet_tag or script_tag to produce complete HTML tags.

{{ 'styles/reset.css' | asset_url | stylesheet_tag }}
{{ 'styles/main.css' | asset_url | stylesheet_tag }}

{{ 'scripts/navigation.js' | asset_url | script_tag }}

asset_url generates a versioned URL that points to the theme's asset storage. stylesheet_tag wraps it in <link>. script_tag wraps it in <script>.

5. Add CSS body classes with body_classes

{{ body_classes }} outputs CSS classes derived from the current template path. Use these classes for template-specific styling.

<body class="{{ body_classes }}">

For templates/event.featured.liquid, this outputs:

<body class="page page-featured">

6. Build navigation

Use navigation to access the page tree. A snippet makes this code reusable:

{% assign nav = navigation %}

<nav class="site-nav" aria-label="Main navigation">
  <ul class="site-nav__list">
    {% for item in nav %}
      <li class="site-nav__item{% if item.has_children %} site-nav__item--parent{% endif %}">
        <a href="{{ item.relativePath | default: item.url }}" class="site-nav__link">
          {{ item.title }}
        </a>
        {% if item.has_children %}
          <ul class="site-nav__submenu">
            {% for child in item.children %}
              <li class="site-nav__subitem">
                <a href="{{ child.relativePath | default: child.url }}" class="site-nav__sublink">
                  {{ child.title }}
                </a>
              </li>
            {% endfor %}
          </ul>
        {% endif %}
      </li>
    {% endfor %}
  </ul>
</nav>

Tenant info, navigation, and global content:

<footer class="site-footer">
  <div class="site-footer__inner">
    <p class="site-footer__copyright">
      &copy; {{ 'now' | date: '%Y' }} {{ tenant.name }}
    </p>
  </div>
</footer>

Complete example

A full layouts/default.liquid for an arts venue site:

<!DOCTYPE html>
<html lang="{{ locale }}">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="{{ page.meta.description | default: '' }}">
  <title>{{ page.title | default: tenant.name }} | {{ tenant.name }}</title>

  {{ content_for_header }}

  {{ 'styles/reset.css' | asset_url | stylesheet_tag }}
  {{ 'styles/main.css' | asset_url | stylesheet_tag }}
</head>
<body class="{{ body_classes }}">
  <a href="#main-content" class="skip-link">Skip to content</a>

  {% render 'announcement-bar' %}
  {% render 'site-header' %}

  <main id="main-content" role="main">
    {{ content_for_layout }}
  </main>

  {% render 'site-footer' %}

  {{ 'scripts/navigation.js' | asset_url | script_tag }}
</body>
</html>

Check the layout

You should have:

  • A layouts/default.liquid that wraps all templates.
  • System content injected via content_for_header.
  • Versioned asset loading via asset_url, stylesheet_tag, script_tag.
  • Navigation rendered from the page tree.
  • Template-specific body classes.

Upload the theme and load any page to verify this. View source to confirm content_for_header output is in the <head>.

Troubleshooting

"Missing layouts/default.liquid": Theme validation requires this file. Create it in layouts/ with at least {{ content_for_layout }} in the body.

Template content does not appear: Confirm the layout includes {{ content_for_layout }} exactly once. That is the injection point.

Assets return 404: Verify the file exists in assets/. Filenames are case-sensitive.

Navigation is empty: navigation returns pages marked as visible in navigation. Confirm pages have Show in navigation enabled in the admin.

On this page