Render - Liquid Tag Reference
On this page
The render simple tag renders a template file inline and explicitly passes variables to it. Unlike the older include tag, render isolates variable scope: only the variables you pass are available inside the rendered template, so the partial is self-contained and reusable without side effects.
Syntax
```liquid
{% render “snippets/product-card”, product: product %} ```
```liquid
{% render “components/form”, action: “checkout”, title: “Review Order”, readonly: false %} ```
| Property | Value |
|---|---|
| Tag Name | render |
| Type | Simple tag |
| Source | Hydrofoil (core) |
How it works
When you render a template, you pass data as named parameters. Those parameters become local variables inside the rendered template. The rendered template cannot see:
- The caller’s
assignvariables - The caller’s loop variables (from
forblocks) - The caller’s capture blocks
But the rendered template can always see:
- Global Liquid variables like
current_store,current_customer,current_cart - Any global objects injected by the controller
- Standard Liquid filters and tags
This isolation makes partials safe to reuse in different contexts without accidentally breaking their behavior.
Parameters and locals
The rendered template receives parameters as locals (local variables available only inside that template). You can pass any Liquid value: strings, numbers, booleans, arrays, objects, and template variables.
```liquid
{% render “checkout/order-summary”, order: current_order, show_shipping: true, items_label: “Items in order” %} ```
Inside the rendered template, those are available as order, show_shipping, and items_label.
Default parameters in snippets
Use the default tag at the top of a rendered snippet to set fallback values for optional parameters:
```liquid
{% render “card”, title: “Default Title”, subtitle: page.description %} ```
In the snippet:
```liquid
{%- default title: “Untitled” -%} {%- default subtitle: “” -%}
{{ title }}
{%- if subtitle %}<p>{{ subtitle }}</p>{%- endif -%} ```
When a parameter is not passed, it takes its default value. When it is passed, the default is overridden.
Composition and recursive rendering
Rendered templates can themselves render other templates, building larger components from smaller ones. This composition pattern is the foundation for reusable theme architecture:
```liquid
{%- render “card-container” -%} {%- render “card”, heading: “Feature One” -%} {%- render “card”, heading: “Feature Two” -%} {%- endrender -%} ```
Rendered templates can also render themselves recursively, useful for tree structures like category hierarchies or nested menus. Pass an array of items and loop over it, rendering the template for each item:
```liquid
{%- for item in items -%} {%- render “tree-node”, node: item, level: level | plus: 1 -%} {%- endfor -%} ```
When to use render
Use render when you want:
- Self-contained partials — pass exactly the data each partial needs, nothing more
- Reusable snippets — the same template can be used in different contexts without interference
- Safe composition — build complex pages by nesting rendered templates
- Testable code — each partial’s behavior depends only on its parameters
Execution context
The render tag runs at template-render time, before the page is sent to the browser. Parameters are passed synchronously, and the rendered output appears inline.
Examples
Render a product card
Pass the product and a title override:
```liquid
{%- for product in collection.products -%} {%- render “products/card”, product: product, show_price: true -%} {%- endfor -%} ```
In snippets/products/card.liquid:
```liquid
{%- default show_price: false -%}
{{ product.name }}
{%- if show_price %} {{ product.pricing.price | money }} {%- endif -%} View```
Render a sidebar with multiple sections
Compose a sidebar from separate section renderers:
```liquid
```
Each renderer in snippets/sidebar/ is isolated and receives only the parameters it needs.
Render a reusable form snippet
Create a form renderer that works across multiple pages:
```liquid
{%- render “forms/text-input”, label: “Email Address”, name: “email”, placeholder: “you@example.com”, required: true -%}
{%- render “forms/text-input”, label: “Phone”, name: “phone”, placeholder: “(555) 000-0000” -%} ```
In snippets/forms/text-input.liquid:
```liquid
{%- default required: false -%}
```
The same form renderer works everywhere because it only depends on its parameters.
Was this article helpful?
Thanks for your feedback! It helps us improve our docs.