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-react

Preview

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 renders 0 if count is zero, Show handles 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>;
Edit on GitHub

Last updated on

On this page