Skip to content

Improve readability of slotted content in snippets #1966

@t-kelly

Description

@t-kelly

👋🏻

I like building compositions from primitives, e.g. a simple text and image section can be quickly thrown together right now in Liquid like:

{% capture content %}
  {% render 'element.text', as:'h2', variant: 'heading-xl', slot: 'Welcome to composable Liquid theme components' %}
  {% render 'element.text', variant: 'rte', slot: '<p>You can compose consistent, high-quality storefronts using well-engineered Liquid components</p>'  %}
{% endcapture %}

{% capture content_stack %}
  {% render 'layout.stack', gap: 'md', slot: content %}
{% endcapture %}

{% capture columns %}
  {% render 'element.image' %}
  {{ content_stack }}
{% endcapture %}

{% capture grid %}
  {% render 'layout.grid', columns_xs: 1, columns_md: 2, gap: 'lg', slot: columns %}
{% endcapture %}

{% render 'layout.section', slot: grid %}

This approach works, but I'm sure we can all agree the syntax is 💩

It would be great if snippets came with a default slot tag, so I could instead write something like this:

{% render 'layout.section' %}
  {% render 'layout.grid', columns_xs: 1, columns_md: 2, gap: 'lg' %}
    {% render 'element.image', img: section.settings.image %}
    {% render 'layout.stack', gap: 'md' %}
      {% render 'element.text', as:'h2', variant: 'heading-xl' %}
        Welcome to composable theme components
      {% endrender %}
      {% render 'element.text', variant: 'rte' %}
        <p>You can compose consistent, high-quality storefronts using well-composed Liquid components</p>
        <a href="#">Click here to learn more</a>
      {% endrender %}
    {% endrender %}
  {% endrender %}  
{% endrender %}

where layout.stack.liquid:

<div class="flex flex-col">{{ children }}</div>

and element.text.liquid:

<{{ as }}>{{ children }}</{{ as }}>

However, from my conversations with @karreiro and @charlespwd, adding an {% endrender %} tag would be a complex and potentially breaking change. We already have other way's of rendering snippets, ie. {% include %}, so what's one more way, right?

Following in suit with {%- ... -%} and {% # ... %} symbol identifiers that have already been introduced, I propose a new tag that emulates an existing open and close pattern most devs are already familiar with,
{%< ... >%}...{%</ ... >%}:

{%< 'layout.section' >%}
  {%< 'layout.grid', columns_xs: 1, columns_md: 2, gap: 'lg' >%}
    {%< 'element.image', img: section.settings.image >%}
    {%< 'layout.stack', gap: 'md' >%}
      {%< 'element.text', as:'h2', variant: 'heading-xl' >%}
        Welcome to composable theme components
      {%</ 'element.text' >%}
      {%< 'element.text', variant: 'rte' >%}
        <p>You can compose consistent, high-quality storefronts using well-composed Liquid components</p>
      {%</ 'element.text' >%}
      {%< 'element.button', text: 'Learn more' >%}
    {%</ 'layout.stack' >%}
  {%</ 'layout.grid' >%}  
{%</ 'layout.section' >%}

I'm not at all married to this specific proposal, but at least let's use it to kickstart some creative thinking?

Why don't I just use slots made possible via theme blocks and {% content_for "block" %}?

Short version -- IMO the theme editor shouldn't be a requirement to make slotting + code-reuse possible in Liquid. It should remain a progressive enhancement that selectively exposes points of configurability in the editor.

  1. I want to build sections and deal with the theme editor layer later. Why do I need to wrangle a ton of JSON configs to just render something on the page. That's a ton of extra work that I don't need for a first prototype. Let me deal with breaking things into blocks later.

  2. I want to have full control when I'm crafting my theme editor experience. I don't want to expose layout.section, layout.grid, and layout.stack as blocks -- I don't think my customers using the editor will care much about those and they'll just add complexity where it's not needed. I'd rather just add a few settings at the section level.

sections/image-with-text.liquid

{%< 'layout.section', padding: section.setting.padding >%}
  {%< 'layout.grid', columns_xs: 1, columns_md: 2, gap: 'lg' >%}
    {% content_for: 'block', type: 'image' %}
    {%< 'layout.stack', gap: 'md' >%}
      {% content_for: 'blocks' %}
    {%</ 'layout.stack' >%}
  {%</ 'layout.grid' >%}  
{%</ 'layout.section' >%}

blocks/image.liquid

{%< 'element.image', img: block.settings.image >%}

blocks/text.liquid

{%< 'element.text', as: block.settings.element, variant: block.settings.variant >%}
  {{ block.settings.text }}
{%</ 'element.text' >%}

blocks/button.liquid

{%< 'element.button', text: block.settings.text >%}

Related issues:

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions