$slots.name works as the whole of a condition. Put it in a compound expression and the condition comes out falsy, whatever the slot's state - so the element silently never renders.
<!-- renders when a toolbar slot is given -->
<th :if="$slots.actions">…</th>
<!-- never renders, even with the slot given and hasRowActions() true -->
<th :if="$slots.actions || hasRowActions()">…</th>
<!-- never renders either -->
<td :if="!$slots.actions && hasRowActions()">…</td>
<template :if="$slots.cell && (!hasSlottedColumns() || column.slotted)">…</template>Isolated by changing one thing: removing $slots.actions || from the first condition above made the column appear immediately, same page, same data, nothing else touched.
Why it is costly to find
Nothing fails. There is no warning, the compiled output contains the element and all its bindings, and stx typecheck is clean. The element is simply absent from the DOM, so it reads as a data problem or a CSS problem.
It also hides behind short-circuiting. A real case from the Stacks dashboard:
<div :if="searchable() || columnToggle() || exportable() || $slots.toolbar">That looks fine and behaves fine for every caller that switches on one of the first three. A caller whose only toolbar content comes from the slot gets no toolbar, and nobody notices for as long as no such caller exists.
In our case a whole feature shipped as a no-op: a declarative row-actions column guarded by :if="$slots.actions || hasRowActions()". Compile probes found every guard and binding in the output, stx typecheck passed, three separate control runs on the compiled template looked right - and the actions column was not on the page. Only driving the live page caught it. See stacksjs/stacks#2924.
Expected
$slots.name evaluates to the slot's presence wherever an expression is allowed, the same as any other value in scope - or, failing that, stx refuses the template rather than compiling a condition it cannot evaluate. Quietly resolving to something falsy is the one outcome that cannot be debugged from the output.
Workaround, for anyone hitting this
Keep every $slots reference standalone and split the branches:
<th :if="$slots.actions">…</th>
<th :else-if="hasRowActions()">…</th>and where a slot needs a fallback, use the slot's own default children rather than a condition:
<slot name="cell" :row="row">
<!-- rendered when the caller supplies nothing -->
</slot>Verified on 0.2.605 (packages/stx, fa8a407bfa) and on the 0.2.534 build installed in the Stacks checkout.
Third one of these: #2095 (slot content loses its ) and #2096 (stx typecheck rejects scoped slot props) are the other two, and together they are why a 729-line table component in Stacks had no callers at all.