Guard

Renders its children only when the condition is false, with an optional alternative to render in its place. Replaces the ternary chains that nest badly inside JSX.

API

Props

proptypedefault
guardIf?booleanfalsewhen true, the children are withheld
thenRender?Renderablenullrendered instead of the children while guarded
shouldHide?booleanfalsewhile guarded, render nothing at all
children?Renderablerendered while not guarded

Examples

Usage

The condition is named after what it withholds, not after what it shows: guardIf reads as the reason to stop. That is the opposite of a ternary, which makes you write the happy path second, and it is why a guard chain stays readable as it grows — every line is a way out, and the children at the bottom are what happens when none of them fires.

tsx
<Guard guardIf={!user} thenRender={SignInPrompt}>
  <Dashboard user={user} />
</Guard>

<Guard guardIf={items.length === 0} shouldHide>
  <ItemList items={items} />
</Guard>

Details

The order of the checks

The three props are read in a fixed order: shouldHide first, thenRender second, the children last. So when both are set, hiding wins and the alternative never renders — worth knowing, because the two look interchangeable at a glance.

tsx
<Guard guardIf={isLoading} shouldHide thenRender={ErrorPanel}>
  <Report data={data} />
</Guard>

Deferred children

Because children is a Renderable, the component form defers the work — the function body never runs while guarded. This is what makes Guard safe around values that only exist once the condition has passed: the non-null assertion below is honest, because nothing evaluates it until the invoice is there.

tsx
<Guard guardIf={!invoice}>{() => <Total amount={invoice!.total} />}</Guard>

With plain JSX children the elements are created before the Guard ever sees them, so the deferral buys you nothing: React still builds the element, it just does not render it. The difference matters when building the subtree is expensive or, as above, impossible.

Guarded with nothing to show

Guarded without a thenRender and without shouldHide, the Guard renders nothing at all. That is the same visible outcome as shouldHide, so reach for the explicit prop when nothingness is the intent: it tells the next reader that the empty branch was considered, not forgotten.