Show
Declarative conditional rendering with fallback support for cleaner JSX.
The Show component provides a clean, declarative alternative to ternary operators and short-circuit evaluation (&&) in React, with built-in fallback support.
Installation
npm install @zayne-labs/ui-reactPreview
Loading...
Usage
The simplest usage takes a when condition and renders children if truthy.
import { Show } from "@zayne-labs/ui-react/common/show";
function Profile({ user }) {
return (
<Show when={user} fallback={<LoginButton />}>
{(nonNullUser) => (
<div>
<h2>{nonNullUser.name}</h2>
<p>{nonNullUser.bio}</p>
</div>
)}
</Show>
);
}For complex layouts with multiple distinct conditions, use the control="content" pattern.
import { Show } from "@zayne-labs/ui-react/common/show";
function DataManager({ state }) {
return (
<Show.Root control="content">
<Show.Content when={state.data}>
{(data) => <DataView items={data} />}
</Show.Content>
<Show.Fallback>
<EmptyState />
</Show.Fallback>
</Show.Root>
);
}Component Source
"use client";import { toArray } from "@zayne-labs/toolkit-core";import { getMultipleSlots, getSingleSlot } from "@zayne-labs/toolkit-react/utils";import { assert, isFunction } from "@zayne-labs/toolkit-type-helpers";export type ShowRootProps<TWhen> = | { children: React.ReactNode; control: "content"; fallback?: React.ReactNode; when?: never; } | { children: React.ReactNode | ((value: TWhen) => React.ReactNode); control?: "root"; fallback?: React.ReactNode; when: false | TWhen | null | undefined; };export function ShowRoot<TWhen>(props: ShowRootProps<TWhen>) { const { children, control = "root", fallback = null, when } = props; if (control === "content" && !isFunction(children)) { const childrenArray = toArray(children) as Array<React.ReactElement<ShowContentProps<TWhen>>>; const foundContentSlot = childrenArray.find((child) => Boolean(child.props.when)); const fallBackSlot = getSingleSlot(childrenArray, ShowFallback); assert( !(fallBackSlot && fallback), "The fallback prop and <Show.Fallback> cannot be used at the same time." ); return foundContentSlot ?? fallBackSlot ?? fallback; } const resolvedChildren = isFunction(children) ? when && children(when) : children; const { regularChildren, slots: [contentSlot, fallBackSlot], } = getMultipleSlots(resolvedChildren, [ShowContent, ShowFallback], { errorMessage: [ "Only one <Show.Content> component is allowed", "Only one <Show.Fallback> or <Show.OtherWise> component is allowed", ], throwOnMultipleSlotMatch: true, }); if (!when) { assert( !(fallBackSlot && fallback), "The fallback prop and <Show.Fallback> cannot be used at the same time." ); return fallBackSlot ?? fallback; } return contentSlot ?? regularChildren;}export type ShowContentProps<TWhen> = Pick<ShowRootProps<TWhen>, "children" | "when">;export function ShowContent<TWhen>(props: ShowContentProps<TWhen>) { const { children, when } = props; const resolvedChildren = isFunction(children) ? children(when as TWhen) : children; return resolvedChildren;}ShowContent.slotSymbol = Symbol("show-content");export function ShowFallback(props: { children: React.ReactNode }) { const { children } = props; return children;}ShowFallback.slotSymbol = Symbol("show-fallback");Component API
Benefits over Logic Operators
- No Zero Rendering: Unlike
count && <div />which renders0if count is zero,Showhandles falsy values correctly. - Improved Readability: Eliminates deeply nested ternaries.
- Type Safety: The render prop automatically narrows types for your data.
// Risky — renders '0' if items is empty
items.length && <List data={items} />;
// Safe
<Show when={items.length > 0}>
<List data={items} />
</Show>;Last updated on