Basker Docs

Build the default layout

Assemble the HTML shell every page shares — head metadata, Open Graph tags, body classes, and the components that wrap your content

A layout is the outer HTML every template renders into. Your theme needs at least one — layouts/default.liquid — and it's where the bits that should appear on every page live: the <head>, global stylesheets, headers, footers.

You'll build it up in pieces.

Step 1 — Create the file

Create layouts/default.liquid and start with a doctype and an empty shell:

<!DOCTYPE html>
<html lang="en">
  <head>
  </head>
  <body>
  </body>
</html>

Save the file. The dev-server browser tab should reload to a blank-but-valid page.

Step 2 — Add the page metadata

The renderer exposes a handful of globals that resolve to the right values for whatever page is being viewed: page_title, page_description, page_image, body_classes. Use them in the <head> so every page gets its own title, social share image, and meta description without you writing per-page code.

Add this to the <head>:

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ page_title }} — My Theatre</title>

<meta name="description" content="{{ page_description }}">
<meta property="og:title" content="{{ page_title }}">
<meta property="og:description" content="{{ page_description }}">
<meta property="og:image" content="{{ page_image }}">

Replace My Theatre with your site's name, or wire it up to a setting later — you'll add a site.name setting on the Variants and theme settings page.

Step 3 — Make space for header injections

Basker injects JSON-LD, the preview banner, generator meta, and similar head-level content via {{ content_for_header }}. Add it as the last line inside <head>:

{{ content_for_header }}

Without this, structured data won't render and the preview banner won't show when you're previewing draft content. The renderer warns about its absence in the dev-server logs.

Create a flat assets/main.css for now:

touch assets/main.css

Reference it from the layout using the asset_url filter. The stylesheet_tag filter wraps the URL in a <link> element with the right attributes:

{{ 'main.css' | asset_url | stylesheet_tag }}

Add that line right above {{ content_for_header }}.

The path you pass to asset_url is relative to your assets/ folder. Nested layouts work too ('css/main.css'), but for the tutorial keep things flat — easier to debug, and Basker's CDN doesn't care either way.

Step 5 — Wire up the body

Now the body. Add a body_classes variable to the opening tag — the renderer fills it with classes derived from the resolved template name, which is useful for per-template CSS hooks like .template-page or .template-event.

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

Most themes split their global UI into reusable components and pull them in with {% render %}. Create two files:

components/global-header.liquid:

<header class="site-header">
  <a href="/" class="site-header__logo">My Theatre</a>
  <nav class="site-header__nav">
    <a href="/about">About</a>
    <a href="/events">What's on</a>
    <a href="/contact">Contact</a>
  </nav>
</header>

components/global-footer.liquid:

<footer class="site-footer">
  <p>&copy; {{ 'now' | date: '%Y' }} My Theatre</p>
</footer>

Then render them from the layout, with the page content sandwiched in between:

<body class="{{ body_classes }}">
  {% render 'components/global-header' %}

  <main class="page">
    {{ content_for_layout }}
  </main>

  {% render 'components/global-footer' %}
</body>

{{ content_for_layout }} is where the rendered template body lands. Without it, only the layout's own markup would show.

components/ and snippets/ are both resolved by the {% render %} tag, so the path prefix tells the renderer which folder to look in. The convention is components/ for larger page-level pieces (header, footer, navigation) and snippets/ for smaller reusable bits (icons, formatters). Use whichever fits the piece you're building.

Step 7 — Final layout

Your layouts/default.liquid should now look like this:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{{ page_title }} — My Theatre</title>

    <meta name="description" content="{{ page_description }}">
    <meta property="og:title" content="{{ page_title }}">
    <meta property="og:description" content="{{ page_description }}">
    <meta property="og:image" content="{{ page_image }}">

    {{ 'main.css' | asset_url | stylesheet_tag }}
    {{ content_for_header }}
  </head>
  <body class="{{ body_classes }}">
    {% render 'components/global-header' %}

    <main class="page">
      {{ content_for_layout }}
    </main>

    {% render 'components/global-footer' %}
  </body>
</html>

What's next

The layout is ready, but {{ content_for_layout }} is empty until you add a template that writes into it. That's the next page: Add page templates.

Going deeper

  • Layouts — alternate layouts, {% layout %} overrides, validation rules.
  • Liquid tags — full reference for render, asset_url, stylesheet_tag, and the rest.
  • Template context — every global available in a layout or template.

On this page