Theme layouts and pages
On this page
A layout is the outermost template that wraps page content in a complete HTML document. It typically contains the <html>, <head>, and <body> elements, along with common elements like the site header, footer, navigation, and asset includes.
Page templates render before the layout. The platform renders the page template into a string, then passes that string as the body_content variable to the layout. The layout wraps the pre-rendered page content — it does not “call” the page.
The default layout
The default layout is layouts/theme.liquid. All pages use this layout unless a page template specifies a different one. Here is a minimal layout:
```liquid
{%- default body_content: nil, csrf_meta_tags: nil, csp_meta_tag: nil -%} {%- default title: nil, meta_keywords: nil, meta_description: nil -%} {%- default sc_support: nil, theme_bar: nil, data: nil -%} {%- default controller: nil, action: nil, id: nil -%} {%- default theme_supplement_stylesheet: nil, theme_supplement_javascript: nil -%} <!doctype html>
{{ csrf_meta_tags }} {{ csp_meta_tag }} {% render "meta_data" %} {%- require "styles/theme.css" %} {{ theme_supplement_stylesheet }} {%- require "scripts/theme.js" %} {{ theme_supplement_javascript }} {{ sc_support }} <body id="{{ id }}" {{ data }}> {{ theme_bar }} {{ "accessibility.skip_to_content" | t | default: "Skip to main content" }} {% render "header" %}```
Required layout variables
The platform passes these variables to layouts/theme.liquid. Declare all of them with {% default %} at the top of your layout to prevent undefined variable errors. Variables marked required will cause visible failures if omitted.
| Variable | Required | Description |
|---|---|---|
body_content |
YES | The fully rendered page template output. Without this, the page appears blank. |
csrf_meta_tags |
YES | HTML <meta> tags containing CSRF tokens. Without this, all form submissions fail. |
csp_meta_tag |
YES | Content Security Policy <meta> tag. |
sc_support |
YES | Platform support scripts. |
theme_bar |
YES | Theme editor and preview bar HTML. Without this, the theme editor breaks. |
theme_supplement_stylesheet |
YES | <link> tag for custom theme CSS (theme-supplement.css). Without this, custom theme styles do not load. |
theme_supplement_javascript |
YES | <script> tag for custom theme JS (theme-supplement.js). Without this, custom theme scripts do not load. |
title |
no | Page title, auto-generated per page type (product name, article title, store name). Used by the meta_data snippet. |
meta_keywords |
no | SEO keywords for the page. |
meta_description |
no | SEO description for the page. |
controller |
no | Name of the controller handling the request (for example products, carts). Useful for body classes or conditional logic. |
action |
no | Controller action name (for example show, index). |
id |
no | Page identifier string, formatted as SC-{controller}-{action} (for example SC-products-show). Intended for the <body> element’s id attribute. |
data |
no | Extra data attributes for the <body> element. |
format |
no | Response format if non-HTML (for example txt, json). |
:::warning
Always output {{ body_content }}, {{ csrf_meta_tags }}, and {{ theme_bar }} in your layout. Omitting any of these causes visible failures: blank pages, broken forms, or a broken theme editor.
:::
Rendering order
- The Liquid controller’s
{% before %}phase runs. - The page template renders into a string.
- The rendered string is passed as
body_contenttolayouts/theme.liquid. - The layout renders, outputting
{{ body_content }}where the page content should appear. - The Liquid controller’s
{% after %}and{% final %}phases run.
Multiple layouts
You can define additional layouts for distinct sections of your site. For example, an account layout that adds a sidebar:
```liquid
{%- comment -%} layouts/account.liquid {%- endcomment -%}
```
Secondary layouts render within the main theme.liquid. The {{ yield }} variable is where the page content appears inside the secondary layout, while the secondary layout’s output becomes body_content in the main layout.
To use a non-default layout, add a {% layout %} tag at the top of the page template:
```liquid
{% layout “account” %} ```
If no {% layout %} tag is present, theme.liquid is used.
Page routing table
Page templates render for specific URL patterns. The file name determines the route mapping.
Core pages
| Page template | URL pattern | Context variable |
|---|---|---|
home.liquid |
/ |
current_page |
product.liquid |
/products/:slug |
current_product |
products.liquid |
/products, /products/category/:path |
current_search, current_product_category |
product_category.liquid |
/products/category/:path |
current_product_category, current_search |
cart.liquid |
/cart |
current_cart |
checkout.liquid |
/checkout, /checkout/:step |
current_cart, current_checkout_step |
order.liquid |
/orders/:token |
current_order |
page.liquid |
/pages/:path |
current_page |
article.liquid |
/articles/:path |
current_article |
article_category.liquid |
/articles/category/:path |
current_article_category |
search.liquid |
/search |
current_search |
account.liquid |
/account, /account/:section |
current_customer, current_account |
location.liquid |
/locations/:slug |
current_location |
locations.liquid |
/locations |
(locations collection) |
not_found.liquid |
any unmatched URL | error |
maintenance.liquid |
when store is in maintenance mode | — |
form_submission.liquid |
/form-submissions/:id |
current_form_submission |
voucher.liquid |
/vouchers/:code |
current_voucher |
subscription.liquid |
/subscriptions/:id |
current_subscription |
Authentication pages
Authentication pages live in the pages/auth/ subdirectory:
| Page template | URL pattern | Purpose |
|---|---|---|
auth/login.liquid |
/login |
Login form |
auth/register.liquid |
/register |
Registration form |
auth/password/forgot.liquid |
/password/forgot |
Forgot password form |
auth/password/reset.liquid |
/password/reset |
Reset password form |
auth/confirmation/pending.liquid |
/confirmation/pending |
Email confirmation pending |
auth/confirmation/resend.liquid |
/confirmation/resend |
Resend confirmation email |
auth/invitation/accept.liquid |
/invitation/accept |
Accept invitation |
auth/invitation/pending.liquid |
/invitation/pending |
Invitation pending |
auth/missing_details.liquid |
/missing-details |
Complete profile after login |
Global variables
These variables are available on every page template:
| Variable | Type | Description |
|---|---|---|
current_store |
StoreDrop | Current store configuration |
current_cart |
CartDrop | Shopping cart |
current_customer |
ContactDrop | Logged-in customer (nil if not logged in) |
current_account |
AccountDrop | Logged-in customer’s account |
current_request |
RequestDrop | HTTP request info (path, params, etc.) |
current_flash |
FlashDrop | Flash messages (notice, alert, error) |
all_products |
Collection | All products |
all_pages |
Collection | All content pages |
all_articles |
Collection | All articles |
all_product_categories |
Collection | All product categories |
all_article_categories |
Collection | All article categories |
all_menus |
Collection | Navigation menus |
all_content_blocks |
Collection | Content blocks |
all_media |
Collection | Media files |
session_variables |
Hash | Session variables (set with {% session %}) |
theme_variables |
Hash | Theme variables |
Checkout steps
The checkout page uses current_checkout_step to determine which step to display:
| Step | Value | Description |
|---|---|---|
| Customer information | "customer_information" |
Collect customer details |
| Shipping information | "shipping_information" |
Select shipping method |
| Accept terms | "accept_terms" |
Terms and conditions |
| Payment information | "payment_information" |
Payment method and submission |
```liquid
{% case current_checkout_step %} {% when “customer_information” %} {% form “checkout-customer-information” %} {% render “checkout/customer_information/form”, form: form %} {% endform %} {% when “shipping_information” %} {% form “checkout-shipping-information” %} {% render “checkout/shipping_information/form”, form: form %} {% endform %} {% when “accept_terms” %} {% form “checkout-accept-terms” %} {% render “checkout/accept_terms/form”, form: form %} {% endform %} {% when “payment_information” %} {% component “checkout/payment_information/page”, reload: “sc.voucher-applied sc.voucher-removed” %} {% endcase %} ```
:::note
The payment information step must use {% component %}, not a {% form %} block. The component handles the payment provider JavaScript that powers the payment fields.
:::
Account sections
The account page uses current_request.params.section to route to different account areas:
| Section | URL | Description |
|---|---|---|
| (default) | /account |
Profile overview |
orders |
/account?section=orders |
Order history |
carts |
/account?section=carts |
Saved carts |
fulfillments |
/account?section=fulfillments |
Fulfillment tracking |
subscriptions |
/account?section=subscriptions |
Subscriptions |
account_credits |
/account?section=account_credits |
Account credits |
account_points |
/account?section=account_points |
Loyalty points |
product_approvals |
/account?section=product_approvals |
Product approval requests |
credentials |
/account?section=credentials |
Change password |
contact |
/account?section=contact |
Edit contact information |
shipping |
/account?section=shipping |
Shipping addresses |
billing |
/account?section=billing |
Billing addresses |
Content-type variants
Some pages support multiple output formats. The variant file renders when the corresponding format is requested:
| File | Content type | Example URL |
|---|---|---|
page.liquid |
HTML | /pages/about |
page.json.liquid |
JSON | /pages/about.json |
page.xml.liquid |
XML | /pages/about.xml |
page.csv.liquid |
CSV | /pages/about.csv |
page.md.liquid |
Markdown | /pages/about.md |
page.text.liquid |
Plain text | /pages/about.txt |
Articles support all the same variants.
Home page
The home page template typically renders the content blocks configured for the store’s home page:
```liquid
{% if current_page != blank %} {{ current_page.body_content }} {% else %}
Configure a home page in your store settings.
{% endif %} ```
The home page is linked to a content page in the store configuration. That content page’s blocks (slideshows, featured products, text sections, and so on) are rendered via body_content.
:::tip
current_page.body_content (used in pages/home.liquid) and body_content (used in layouts/theme.liquid) are different variables. The first renders the CMS content blocks on the page object. The second is the fully rendered page template output passed to the layout.
:::
Was this article helpful?
Thanks for your feedback! It helps us improve our docs.