ChaiBuilder Logo

Conditional Visibility

Every block can be hidden - permanently, or based on the data the page is rendering with. A "Sold out" badge that only appears when stock is zero, a featured banner that only appears on featured posts, a download section that only appears when the record has a file attached.

There are two levels to this, and they use the same setting.

What it is When to use it
Toggle A plain on/off switch Park a block you are not ready to publish
Condition A data path, optionally piped through a boolean pipe Show the block only for records that qualify

Hiding a block outright

The Visibility switch sits near the top of the block settings panel. Switch it off and the block stays in the page - editable, still in the outline - but does not render.

The same toggle is on every row of the Outline panel as an eye icon, which is the faster way to hide something several levels deep, and in the block's right-click menu.

This is the right tool for work in progress. It is not a draft mechanism for content - if a whole section is not ready, hiding it is fine, but remember it stays hidden after publish until someone switches it back on.

Adding a condition

Click the small gear beside the Visibility switch. The popover reads "Conditional Visibility - Choose a boolean data path or add boolean pipes. The block is visible only when the result is true."

A condition is written the same way as a data binding: a data path, optionally piped through pipes. The difference is that it has to end up as a real boolean.

blog.featured
global.showAnnouncementBar
blog.status | equals 'published'
blog.price | gt 0
blog.tags | empty | not
blog.downloadUrl | truthy

Above the input, a row of chips lists the top-level keys available on this page with their types, so you do not have to guess whether it is blog or post, and typing a path opens an autocomplete that drills into it. Below the input, the same formatter editor used by binding badges appears: Add formatter, argument controls, reordering, and a live Preview of the result. The field validates as you type, so an unknown pipe, a bad argument, or a condition that does not produce a boolean is flagged before you can save.

Once saved, the Visibility row shows the condition inline as a small code chip with the note "visible when true", and the on/off switch is disabled - a block cannot be both conditionally shown and manually toggled. The trash icon in the popover removes the condition and returns the block to always visible.

Conditions read the same data as bindings: page type data, global.*, and $index inside a repeater.

The visible-only-when-true rule

This is the part worth reading twice.

The block renders only when the condition resolves to the boolean true. Everything else hides it: false, a missing field, a string, a number, a broken pipe, an expression that is not valid at all.

Condition result Block
true shown
false hidden
"published" (a string, even a non-empty one) hidden
0 or 1 hidden
missing field hidden
invalid condition hidden

So {{blog.featured}} works only when featured is genuinely a boolean field. Point a condition at a text or number field and the block disappears, whatever the value. That is what the boolean pipes are for: they turn any value into a real true or false.

Pipe Argument True when
equals a literal The value is exactly the argument. No type coercion, so '5' does not equal 5
notEquals a literal The value is anything other than the argument
gt / gte / lt / lte a number The numeric comparison holds. Numeric strings are converted; anything non-numeric is false
not - The value is falsy
truthy - The value is truthy
empty - The value is null, undefined, "", or an empty array

Value pipes can run first, as long as a boolean pipe finishes the chain:

blog.title | trim | empty | not
blog.tags | join ',' | truthy

There is no && or ||. A condition is one path and one chain of pipes, so two independent rules cannot be combined in the panel. When you need "featured and published", expose a single computed boolean from the data provider (isPromoted) and bind to that. It is cheaper too: the provider computes it once per request.

The rest of the rules are the binding rules from Paths and pipes: no JavaScript, no brackets (blog.tags.0, not blog.tags[0]), literal pipe arguments only, and a 500 character maximum.

What "hidden" means on the page

A block that fails its condition is not rendered at all. It is absent from the HTML, not present-and-hidden with display: none.

That has consequences worth knowing:

  • The block's content is not in the page source, so it is not indexed, not read by screen readers, and does not count toward page weight.
  • Its images are not requested.
  • There is no way to reveal it later on the client. Visibility is decided at render, not in the browser.

Conditions are not personalization. They are evaluated when the page is rendered against that page's data, and the result is cached and served to every visitor identically. A condition cannot depend on who is viewing, what is in their cart, or what time it is for them. If you need per-visitor behaviour, that belongs in a custom block that runs on the client. See Custom blocks and Caching and revalidation.

In the builder canvas

Conditionally hidden blocks behave differently in the builder on purpose - you need to be able to edit a block you cannot currently see.

  • With the binding preview toggle (the lightning bolt in the canvas top bar) off, conditions are not evaluated and every conditional block stays visible so you can work on it.
  • With it on, conditions run against the current page's data and blocks appear or disappear the way they will on the published page.

Flip it on before publishing to check that the sections you expect are actually there.

To find every conditional block on a page, use the filter in the Outline panel - it can narrow the tree to blocks that are hidden or carry a condition. That is the fastest way to audit a page someone else built, or to work out why a section is missing.

Repeaters

Inside a repeater, a condition can reference the current item with $index:

$index.featured
$index.stock | gt 0
$index.badge | equals 'new'

The condition is evaluated per item, so a badge inside a card template appears only on the cards that qualify.

Partials

A condition set on a partial's reference applies to everything the partial contains. Hiding a partial on one page hides that whole block group on that page, without changing the partial itself or any other page using it.

Conditions written before pipes

Earlier versions accepted a small subset of JavaScript here, so conditions like blog.featured === true or blog.tags.length > 0 were normal. That engine has been removed and those conditions are now invalid, which means the blocks carrying them are hidden, not shown. Rewrite them:

Old condition Now
blog.featured === true blog.featured (if the field is a boolean)
blog.status === 'published' blog.status | equals 'published'
blog.status !== 'draft' blog.status | notEquals 'draft'
blog.price > 0 blog.price | gt 0
blog.downloadUrl !== undefined blog.downloadUrl | truthy
blog.tags.length > 0 blog.tags | empty | not
!blog.featured blog.featured | not
a === true && b === true one computed boolean from the data provider

Because the failure direction flipped - old conditions used to fail open, new ones fail closed - a page that upgraded without a pass over its conditions loses sections rather than showing extra ones. The Outline filter lists every conditional block on a page, which is the quickest way to work through them.

Gotchas

A missing field now hides the block. This is the reverse of the old behaviour, where anything that was not exactly false showed it. A typo in a path silently removes a section instead of leaving it visible.

A non-boolean value hides the block. blog.status on its own hides the block even when the status is published, because a string is not true. Finish the chain with a boolean pipe.

Draft data can mislead you. The builder loads data in draft mode. A condition like blog.status | equals 'published' behaves differently in the canvas than on the live site.

Hiding is not access control. A hidden block is absent from the page, which is good, but visibility conditions run on page data - they are not a permissions system and should not be used to gate content that specific people should not see. Use roles and permissions for that.

The manual toggle and a condition are mutually exclusive. Setting a condition disables the switch. Remove the condition with the trash icon before you can toggle by hand again.

An empty condition clears it. Saving a blank input returns the block to always visible rather than hiding it.

Verify

  1. With binding preview on, the canvas matches what you expect for the current record.
  2. Open a second record of the same page type - a condition that is wrong usually still looks right on the one record you built it against.
  3. On the published page, view source and confirm the block is genuinely absent, not just invisible.
  4. Use the Outline filter to list conditional blocks and confirm none were left behind from an earlier draft.
  • Data binding - the data conditions are written against
  • Pipes - full reference for the boolean pipes, and registering your own
  • Blocks - block settings and the outline panel
  • Preview and publish - checking a page before it goes live
  • Custom blocks - client-side behaviour that conditions cannot cover

© ChaiBuilder. All rights reserved.