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 }}: Remarkable 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 Remarkable 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 after your page metadata and before your stylesheets:
{{ content_for_header }}Without this, structured data won't render and the preview banner won't show when you're previewing draft content.
Step 4: Link a stylesheet
Create a flat assets/main.css for now:
touch assets/main.cssReference 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 after {{ 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. This is 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. A base template produces page; named template parts add classes such as page-featured, making useful variant-specific CSS hooks.
<body class="{{ body_classes }}">
</body>Step 6: Render the global header and footer
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">Remarkable 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>© {{ 'now' | date: '%Y' }} Remarkable 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 }}: Remarkable 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 }}">
{{ content_for_header }}
{{ 'main.css' | asset_url | stylesheet_tag }}
</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.