Liquid reference

Themes use standard Liquid (tags like if, for, assign, capture, render, and filters like escape, default, date, json…) plus the filters and tags below, and the platform's objects. Always escape text you output in HTML unless it's HTML on purpose (rich text settings, page.content).

Objects

Every object a theme can read (firm, settings, customer, page, section, block and the rest) is documented, property by property, in the Objects reference.

Filters

Filter Example Result
asset_url {{ 'theme.css' | asset_url }} URL of a file in assets/ (cached for a year, changes with every version)
stylesheet_tag {{ 'theme.css' | asset_url | stylesheet_tag }} <link rel="stylesheet">
script_tag {{ 'theme.js' | asset_url | script_tag }} <script defer> with the page's nonce
t {{ 'team.members_count' | t: count: 12 }} Text from locales/en.default.json, with {{ count }} filled in
money {{ 49 | money }} $49.00 in the firm's currency
font_face {{ settings.body_font | font_face }} <link> loading a font_picker font
font_family {{ settings.body_font | font_family }} The CSS font-family stack
color_readable {{ settings.color_primary | color_readable }} #0f172a or #fff, whichever reads better on the colour
video_embed_url {{ section.settings.video | video_embed_url }} The player URL of a YouTube or Vimeo link, or empty
local_date {{ 'now' | local_date: 'F Y' }} A date in the firm's timezone (PHP date format)
handleize {{ 'Hello World' | handleize }} hello-world
json {{ firm.name | json }} JSON, safe inside <script>
image_url {{ section.settings.image | image_url: width: 800 }} The image URL (images are already web-sized)

Tags

Tag Use
{% schema %}…{% endschema %} A section's settings, blocks and presets (JSON).
{% sections 'header-group' %} Render a section group.
{% section 'name' %} Render a section with its default settings.
{% render 'snippet', var: value %} Render a snippet.
{% stylesheet %}…{% endstylesheet %} CSS for a section, collected into one <style> in <head>.
{% javascript %}…{% endjavascript %} JavaScript for a section, added to the page with its nonce.
{% form 'type', class: '…' %}…{% endform %} A form posting to the platform (below).

Forms

{% form %} outputs a <form> with the right action, method and security token. Inside it, a form object has posted_successfully, errors (by field) and values (what was entered, to fill the fields again).

Type Fields
contact name, email, message
intake name, email, phone, practice_area_id, answers[{key}] for each of intake_form.questions, and the hidden spam trap company_website
customer_login email, password, remember
recover_customer_password email
reset_customer_password token and email (hidden, from reset_password), password, password_confirmation
activate_customer_password token (hidden, from invitation), password, password_confirmation, accept_terms, marketing_consent (optional)
resend_verification (none)
customer_logout (none)
Liquid
{% form 'contact', class: 'grid gap-4' %}
  {% if form.posted_successfully %}<p role="status">{{ 'contact.success' | t }}</p>{% endif %}
  <label for="contact-email">Email</label>
  <input id="contact-email" type="email" name="email" value="{{ form.values.email | escape }}" required>
  {% if form.errors.email %}<p>{{ form.errors.email | escape }}</p>{% endif %}
  …
  <button type="submit">Send</button>
{% endform %}

Counsel's sections/main-*.liquid files show every form in full.

Submit states

Every {% form %} gets a submit state from the platform, with nothing to add to your theme:

  • While the form is sent, the <form> has aria-busy="true", and the button that sent it gets the class is-loading, aria-disabled="true" and a small spinner (an ::before in the button's text colour).
  • A second submit while the first is on its way is ignored, so a double click can't send the form twice.
  • The button isn't disabled, so its name and value are still posted.
  • Coming back to the page with the browser's Back button resets the form.

Style the state with form[aria-busy='true'] .is-loading (for example, to replace the spinner, set content: none on its ::before). To leave a form out, for instance one your own script submits with fetch(), add data_no_submit_state: true; underscores become dashes, so the form gets data-no-submit-state:

Liquid
{% form 'contact', data_no_submit_state: true %}…{% endform %}

If your script calls event.preventDefault() on the submit event, the platform leaves that submit alone.

Text and translations

Put your theme's text in locales/en.default.json and output it with t:

JSON
{ "team": { "members_count": "{{ count }} lawyers" } }

Text the firm should be able to change belongs in settings instead.

Still need help?

Send a request to the Mattersimple team and we'll reply by email.

Sign in to contact support