Show (Conditional Rendering)
Render content conditionally based on a signal.
Basic Usage
import { createSignal, Show } from '@luna_ui/luna';
function Toggle() {
const [visible, setVisible] = createSignal(false);
return (
<div>
<button onClick={() => setVisible(v => !v)}>
Toggle
</button>
<Show when={visible()}>
<p>Now you see me!</p>
</Show>
</div>
);
}
Fallback Content
Show alternate content when the condition is false:
<Show when={isLoggedIn()} fallback={<LoginForm />}>
<Dashboard />
</Show>
Extracting Values
When the condition is a value (not just boolean), you can access it:
const [user, setUser] = createSignal(null);
<Show when={user()} fallback={<p>Loading...</p>}>
{(u) => <p>Welcome, {u.name}!</p>}
</Show>
The render function receives the truthy value, guaranteed to be non-null.
Why Show vs Ternary?
You might wonder why use <Show> instead of a ternary:
// Ternary - works but has downsides
{visible() ? <Content /> : <Fallback />}
// Show - preferred
<Show when={visible()} fallback={<Fallback />}>
<Content />
</Show>
Benefits of Show
Lazy Evaluation: Children only render when condition is true
Cleaner Syntax: Especially for complex conditions
Keyed Rendering: Can preserve or reset state
Keyed Show
By default, Show preserves DOM nodes when toggling. Use keyed to force recreation:
const [tab, setTab] = createSignal("home");
// Preserved: same component instance, state retained
<Show when={tab() === "home"}>
<Counter />
</Show>
// Keyed: new instance each time, state reset
<Show when={tab()} keyed>
{(currentTab) => <TabContent tab={currentTab} />}
</Show>
Nested Conditions
<Show when={user()}>
<Show when={user().isAdmin} fallback={<UserDashboard />}>
<AdminDashboard />
</Show>
</Show>
Common Patterns
Loading States
const [loading, setLoading] = createSignal(true);
const [data, setData] = createSignal(null);
const [error, setError] = createSignal(null);
<Show when={!loading()} fallback={<Spinner />}>
<Show when={!error()} fallback={<ErrorMessage error={error()} />}>
<DataView data={data()} />
</Show>
</Show>
Feature Flags
const [features] = createSignal({ newUI: true, beta: false });
<Show when={features().newUI}>
<NewHeader />
</Show>
<Show when={features().beta}>
<BetaFeature />
</Show>
Auth Guards
const [user, setUser] = createSignal(null);
<Show when={user()} fallback={<Navigate to="/login" />}>
{(u) => (
<Show when={u.verified} fallback={<VerifyEmail />}>
<App user={u} />
</Show>
)}
</Show>
Show vs CSS Display
| Approach | DOM | State | Use When |
|---|---|---|---|
<Show> | Added/removed | Reset (or keyed) | Content expensive to render |
style={{ display }} | Always present | Preserved | Frequent toggles, state preservation |
// DOM removed when hidden
<Show when={visible()}>
<HeavyComponent />
</Show>
// DOM hidden but present
<div style={{ display: visible() ? "block" : "none" }}>
<LightComponent />
</div>
Try It
Create a login/logout toggle that shows different content based on auth state:
Solution
function AuthExample() {
const [user, setUser] = createSignal(null);
const login = () => setUser({ name: "Alice", role: "admin" });
const logout = () => setUser(null);
return (
<div>
<Show
when={user()}
fallback={
<div>
<p>Please log in</p>
<button onClick={login}>Log In</button>
</div>
}
>
{(u) => (
<div>
<p>Welcome, {u.name}!</p>
<Show when={u.role === "admin"}>
<p>Admin Panel</p>
</Show>
<button onClick={logout}>Log Out</button>
</div>
)}
</Show>
</div>
);
}
Next
Learn about For (List Rendering) โ