visible_if Deep Dive
"visible_if": "{{ reader.interests contains 'liquid' }}"
If you're unaware - Shopify themes can now have conditional settings via the new visible_if
property.
I know you're dying to celebrate after reading this, but let's dive deeper first, and throw a party after.
visible_if
allows us to improve the merchant experience within the theme editor by showing/hiding settings as and when they become relevant.
Anybody who's built a Liquid theme before will have come across this classic scenario: a section needs to support either an image or a video. Previously you'd have to show both inputs in the theme customiser regardless of which is being used. Now you can hide one when the other is populated, or have a separate switch allowing the merchant to toggle between the input types.
visible_if
is particularly handy for lengthy schemas, overloaded with options. For example, previously you might show 5 or 6 custom typography settings just in case the merchant wants to use them. Now you can hide them when they're irrelevant.
How do I use visible_if
?
visible_if
can be added to any schema setting like this
{
"label": "Image",
"id": "image_picker",
"type": "image",
"visible_if": "{{ section.settings.media_type == 'image' }}"
}
This example is checking if a setting with the ID media_type
is set to image
. If it is, the image input will be visible.
It's important to note the name of the property: visible_if
. The name highlights that the condition only affects whether the setting is shown/hidden in the theme editor. The value assigned to the setting will be available to use in liquid regardless of whether the input is visible or not.
In the previous example you'd need to add an additional check when rendering the image in your template, to avoid rendering it if media_type
was set to video
instead.
{%
if section.settings.media_type == 'image'
and section.settings.image != blank
%}
{{ section.settings.image | image_url: width: 800 | image_tag }}
{% endif %}
It's also important to note that visible_if
cannot access resources, so for example, you can't use {{ section.settings.product.tags contains 'recyclable' }}
.
You can still use the product handle in the comparison though, because this is saved in your settings JSON. I'd discourage encoding information in the handles for products and other resources, but I've seen enough builds in my time somebody is going to do it.
What expressions can I use?
Think of visible_if
like an opening if
tag - without the if
, and with double curlies instead of curly percentages (is there an actual name for this?).
You can use the ==
, !=
, >
, >=
, <
, <=
and contains
comparators, and you can use and
and/or or
.
You can't use Liquid filters in there, so there's no doing {{ 'now' | date > 12345 }}
I'm afraid.
When should I use visible_if
?
visible_if
is primarily a tool for improving the merchant experience.
It's easy for schemas to suffer from setting bloat over time, and this can be quite painful if left unaddressed. If you've ever scrolled through a 30 setting section just to make 1 small edit, you've definitely wondered if there could be a better way.
With visible_if
we have more opportunities to manage this experience. Surfacing settings only when they're relevant to a given context.
What else could I use visible_if
for?
If you know me, you'll know I'm not satisfied to simply use theme features for their intended purpose. I love exploring alternative use cases, and found myself inspired to dig and find alternative uses.
Hidden settings
{
"label": "Wishlist API URL",
"id": "wishlist_api_url",
"type": "url",
"visible_if": "{{ false }}"
}
Alright, let's start with this less than obvious one.
With this one we can hide a setting all the time. "Why would I want to do that?" I hear you ask, with a baffled expression on your face no doubt.
During my time building themes in agencies, we'd often use theme settings for data that we needed access to throughout a theme, but we didn't want the merchant to actually edit. For example these could be third party API urls, or public API keys.
Alternatively for merchants with the same theme deployed to multiple stores, this can be used as an interface to provide other store specific settings that aren't meant to be edited on a whim.
"visible_if": "{{ false }}"
lets us do this without worrying about accidental merchant edits, because the setting will never be visible.
Settings validation and documentation
I ran into a scenario recently where I had a block with a url
setting, allowing the entire block to be a link, but the text inside was provided by an inline_richtext
setting.
inline_richtext
supports links and there's no way to hide the url
setting when the richtext contains a link, because there's no way to express "doesn't contain a link" in a one line expression.
I needed to warn the merchant about a potential accessibility issue in this scenario. I settled on using the following paragraph setting which is only visible when a problematic combination occurs
{
"content": "Accessibility issue: Your text contains a link, but the block is a link too. Please remove one.",
"type": "paragraph",
"visible_if": "{{ block.settings.text contains '</a>' and block.settings.link != blank }}"
}
Since it animates in, the merchant is more likely to notice and read it, than if it was a static block that's ever present.
As an alternative to validation, you may also want to use this for surfacing documentation when certain settings are used, giving merchants information when it becomes relevant, rather than a big, separate explainer article documenting all possible scenarios.
{
"content": "To configure which loyalty groups can see this, visit [Loyalty App](https://link.to.loyalty/app)",
"type": "paragraph",
"visible_if": "{{ block.settings.restrict_to_eligible_loyalty_tiers }}"
}
Pseudo settings accordions
If you have a really long schema, you could just use toggles with no actual impact on the rendered Liquid to show/hide groups of settings. This is similar in behaviour to grouping settings inside accordions, just that the accordion toggle is a checkbox instead.
[
{
"label": "Show video settings",
"id": "show_video_settings",
"type": "checkbox"
},
{
"label": "Autoplay",
"id": "autoplay",
"type": "checkbox",
"visible_if": "{{ block.settings.show_video_settings }}"
},
{
"label": "Mute",
"id": "mute",
"type": "checkbox",
"visible_if": "{{ block.settings.show_video_settings and block.settings.autoplay == false }}"
},
{
"label": "Loop",
"id": "loop",
"type": "checkbox",
"visible_if": "{{ block.settings.show_video_settings }}"
}
]
In most cases you're more likely to tie this to a functional setting. For example with this video, you could show the video options if the video is actually populated. I'm sure somebody out there can take advantage of this though.
What's visible to visible_if
?
The examples of visible_if
I've seen all reference section or block settings, but visible_if
does have a little bit more information available to it.
visible_if
allows you to cross reference your theme, block and section settings. This means you could for example, only show a setting related to a third party API, if it's enabled via theme settings.
// blocks/product-card.liquid
{
"label": "Show wishlist button",
"id": "show_wishlist_button",
"type": "checkbox",
// Referencing theme settings from a block? Ooof!
"visible_if": "{{ settings.wishlist_enabled }}",
}
Similarly you can make a block setting visibility depend on a parent section setting.
// sections/vip-section.liquid
{
"label": "VIP Customers only",
"id": "vip_customers_only",
"type": "checkbox",
"default": true,
// This should always be enabled, so child blocks can hide certain config options
"visible_if": "{{ false }}"
}
// blocks/some-custom-block.liquid
{
"label": "Customer Type",
"id": "customer_type",
"type": "select",
"options": [],
"visible_if": "{{ section.settings.vip_customers_only != true }}"
}
I can picture this being used to allow a block to be reused across multiple sections, with one-off schema differences depending on their context. I can also imagine this approach making things difficult to manage properly - use it responsibly.
I can't think of a use case for this one, but you can also only show a theme setting if a section setting has the correct value
// config/settings_schema.json
{
"label": "Super secret setting",
"id": "super_secret_setting",
"type": "text",
// Referencing a section setting? In theme settings? Has science gone too far?
"visible_if": "{{ section.settings.text contains 'the password' }}",
}
This is a funky one. The theme setting will always be hidden when accessed directly, and only be available under "Theme Settings" in the section sidebar when a section has a "text" setting which contains "the password", and the section template is actually using that theme setting.
As with so many development challenges, knowing what data we have, and where we can use it is a big part of solutioning. Whilst visible_if
doesn't have access to all scopes, it has access to more than you might have expected. Hopefully the less conventional use cases here will inspire more ideas and creative solutions. If you've found any alternative uses please tweet me, I'd love to hear about them.