Skip to content

Add squish filter#2050

Merged
graygilmore merged 1 commit into
Shopify:mainfrom
bakura10:squish-filter
Mar 6, 2026
Merged

Add squish filter#2050
graygilmore merged 1 commit into
Shopify:mainfrom
bakura10:squish-filter

Conversation

@bakura10
Copy link
Copy Markdown
Contributor

@bakura10 bakura10 commented Feb 19, 2026

Hello,

This PR provides a clean solution to #2040

This PR answers a common use case we're facing with Shopify themes. As themes now become more complex, it is often needed to compose classes or inline styles, for instance using capture tags:

{% capture styles %}
   --foo: {% if section.settings.foo %}10%{% else %}20%{% endif %};
   --bar: 10px;
{% endcapture %}

This, however, messes with whitespace. While this technically works, this makes it harder to debug. Horizon (Shopify free theme), especially, has this problem:

image

There are workarounds but they are fragile:

  • You can use whitespace controls {%- -%} but they won't work in some cases (for instance in this capture example) and it is also easy to forget a -%}.
  • You can use this solution but this is verbose and probably quite inefficient on long strings: {% foo | strip_newlines | split: ' ' | join: ' ' %}

This PR adds a new filter. The name follows the one from Ruby on Rails (https://api.rubyonrails.org/classes/String.html#method-i-squish) and offers a simple, elegant solution:

<div style="{{ style_attribute | squish }}">
</div>

I've signed the CLA. The associated documentation PR is #2051

@rylanharper
Copy link
Copy Markdown

Does this also work for inline conditional styles using class? Something like this (from the referenced issue):

<nav
  aria-label="Main navigation"
  class="hidden grid-cols-[1fr_max-content_1fr] [grid-template-areas:'left_center_right'] gap-12 h-full lg:grid
  {% if header_width == 'page' %} container mx-auto {% else %} px-6 {% endif %}
  {% if header_spacing == 'compact' %} min-h-8.5 {% else %} min-h-10.5 {% endif %}
  {% if header_text_style == 'uppercase' %} uppercase {% endif %}
  "
>
  // ... nav code
</nav>

@bakura10
Copy link
Copy Markdown
Contributor Author

Nope. For this you will probably need to capture first the class and then output it:

{% capture class %}
hidden grid-cols-[1fr_max-content_1fr] [grid-template-areas:'left_center_right'] gap-12 h-full lg:grid
  {% if header_width == 'page' %} container mx-auto {% else %} px-6 {% endif %}
  {% if header_spacing == 'compact' %} min-h-8.5 {% else %} min-h-10.5 {% endif %}
  {% if header_text_style == 'uppercase' %} uppercase {% endif %}
{% endcapture %}

<nav aria-label="Main navigation"  class="{{ class | squish }}">
  // ... nav code
</nav>

@stefanroberts
Copy link
Copy Markdown

Completely agree this is needed (the Horizon whitespace issue is a real headache sometimes) and this is a nice easy elegant solution.

@stephanie-shopify stephanie-shopify requested a review from a team March 4, 2026 20:35
Copy link
Copy Markdown
Contributor

@graygilmore graygilmore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me, thanks for the contribution.

@graygilmore graygilmore merged commit 3e76244 into Shopify:main Mar 6, 2026
1 check passed
@rylanharper
Copy link
Copy Markdown

rylanharper commented May 11, 2026

@graygilmore has this been implemented into Liquid yet or no? Just checking in on this feature. I see its merged, but I can't find a reference to it in the docs online.

@graygilmore
Copy link
Copy Markdown
Contributor

@rylanharper haven't merged the docs yet! In fact I'm considering changing the implementation just a bit to include unicode whitespace, too (as well as updating strip, lstrip, and rstrip to do the same).

@rylanharper
Copy link
Copy Markdown

@graygilmore That sounds good! While the new squish filter is a welcome addition for general whitespace control, it doesn't fully address the core issue in #2040, which is automatic whitespace normalization for CSS class strings in Liquid specifically.

The problem is that developers using Tailwind write dynamic if/else class logic in Liquid and indent it for readability, which leaves extra whitespace in the rendered class string. Ideally, class strings should automatically collapse all whitespace to single spaces, as other frameworks do.

I think both this filter and a built-in solution can coexist as they solve slightly different things. My main concern is that #2040 gets closed prematurely if squish is seen as the fix, when the underlying need isn't fully met yet.

@graygilmore
Copy link
Copy Markdown
Contributor

Unfortunately the example code in #2040 isn't valid Liquid. You can't use {% %} inside of {{ }}, this raises a Liquid syntax error. But if you tweak that a little bit you can definitely use squish to solve the issue:

{%- capture classes -%}
  hidden lg:grid
  {% if header_width == 'page' %} container mx-auto {% else %} px-6 {% endif %}
  {% if header_spacing == 'compact' %} min-h-8.5 {% else %} min-h-10.5 {% endif %}
  {% if header_text_style == 'uppercase' %} uppercase {% endif %}
{%- endcapture -%}

<div class="{{ classes | squish }}"></div>

Would render like this:

Liquid::Template.parse(template).render
=> "<div class=\"hidden lg:grid px-6 min-h-10.5\"></div>"

Unless I'm missing something I believe squish does in fact close that issue out.

@rylanharper
Copy link
Copy Markdown

Ahh got it, yeah I guess you're right! Maybe I should just submit a new issue off this then (or maybe not). In that example, the Tailwind classes are unreadable by an IDE's Tailwind IntelliSense (though it can be configured in VS Code settings):

{%- capture classes -%}
  hidden lg:grid
  {% if header_width == 'page' %} container mx-auto {% else %} px-6 {% endif %}
  {% if header_spacing == 'compact' %} min-h-8.5 {% else %} min-h-10.5 {% endif %}
  {% if header_text_style == 'uppercase' %} uppercase {% endif %}
{%- endcapture -%}

<div class="{{ classes | squish }}"></div>

Either way, the original issue was mainly to highlight that working with Tailwind in Liquid is harder than it should be. Things like whitespace control for class strings should probably be default behavior (inconsistent indentation can silently break styles), and there's nothing in the Shopify/Liquid docs covering how to use Tailwind properly. A new dev likely wouldn't know that squish or if/else can even be used for class composition.

Not knocking squish at all, it's a great filter. I just don't think there's a clear, overarching answer for Tailwind in Liquid yet. Worth keeping in mind 🤷‍♂️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants