Improve readability of slotted content in snippets
Nobody has claimed this yet.
- Dominant language
- Ruby
- Stars
- 11.9k
- Forks
- 1.5k
- Avg merge
- 17h 55m
- Merged PRs (30d)
- 3
Description
👋🏻
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.
-
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.
-
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:
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the related issues 1854, 1829, and 1565, then compare the proposed nested snippet syntax with the existing render, include, and content_for examples in this issue. Done means the project has agreed on a concrete slotting syntax and its compatibility and implementation scope, rather than only a collection of proposals.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ruby
- Domain
- developer-experience
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 28/100