The layout tag.
Coming The {% layout %} tag and its content_for_layout slot are a proposed feature, not a shipped one. This page describes the planned model so you know what is coming, and it is explicit about why you must not build on the tag yet.
Not usable yet. On a Standard site today, {% layout %} resolves against your templates but drops the wrapped body, so a template that relies on it renders its content blank. On a Compat site the directive is stripped. Do not build on the tag until it ships. Use partials or type-based layouts instead.
Status
This is a design, not a released feature, and the details here are subject to change before it ships. The tag is planned for Standard mode only and depends on the standard-mode template filesystem and render budget that already ship. It exists today only in the sense that the engine recognises the tag name; the behaviour below has not been built.
The reason the tag is gated off rather than half-working is that the underlying Liquid engine's native {% layout %} is block-based and leaves content_for_layout empty, which is why it currently drops the body. The plan is to ship a FleekSite tag that implements the slot model described here instead.
The proposed model
The design follows the layout model theme authors know from other platforms. A content template declares a layout and provides only its own body; a separate layout template renders the page chrome and drops the content into a content_for_layout slot.
{% comment %} PROPOSED: a content template opts into a layout {% endcomment %}
{% layout 'theme' %}
class="post">
class="post-title">{{ title }}
>
{{ body }}
>{% comment %} PROPOSED: the layout template titled "theme" renders the chrome {% endcomment %}
>
>
>>{{ site.name }} >>
>
{% partial header %}
{{ content_for_layout }}
{% partial footer %}
>
>Under the plan, {% layout 'theme' %} emits nothing itself and records the layout name for the render (the first occurrence wins). Once the content template has rendered to a string, the pipeline resolves the template titled theme and renders it with content_for_layout set to that string. The output is the layout's render.
Planned behaviour
- Explicit opt-in. Nothing wraps a template unless it declares a layout. The first version has no site-wide default layout.
- Opting out.
{% layout none %}renders the body unwrapped, and so does having no directive at all. - Missing layout. If the named layout template does not exist, the content renders unwrapped and the miss is logged. It never blanks the page, matching how
{% partial %}handles a missing template. - Shared context. The layout renders in the full page context (
site,page,bits,params) withcontent_for_layoutadded, like a partial and unlike the isolated{% render %}. - Nesting. A layout may itself declare a layout, so layouts can inherit. Nesting is bounded by the render budget and an explicit depth cap.
- Standard only. On a compat site the directive is stripped and the body renders unchanged, byte for byte with today.
- Literal names. The name is a literal (
'theme'ornone). Dynamic layout names are not part of the first version.
What to use today
Until {% layout %} lands, build page chrome the way current themes do. Two shipped patterns cover it:
- Include shared chrome with partials: a header and a footer pulled in by title with
{% partial %}(or native{% include %}on a standard site). - Let the pipeline wrap posts for you with type-based layouts: a post of a given type is rendered through the template whose permalink matches its type, with no directive needed.
Both are stable and are what themes rely on now. When {% layout %} ships it will complement type-based resolution rather than replace it, the same way it does on the platforms it is modelled on.