@hbi-developer/react-switch-component
A zero-dependency Switch component for React — declarative conditional rendering that reads like native `switch`
Table of Contents
- Overview
- Why This Library
- Features
- Installation
- Quick Start
- How It Works
- Examples
- API Reference
- Development
- Contributing
- License
- Support
Overview
@hbi-developer/react-switch-component brings the familiar switch statement pattern to React JSX. Instead of nested ternaries or long chains of && conditions, you describe each branch as a component — readable, composable, and type-safe.
The library ships with zero runtime dependencies beyond React itself. It is built for performance: only the matched branch is rendered, with optional transition delays for animation libraries.
import { Switch } from "@hbi-developer/react-switch-component";
function StatusView({ status }: { status: "loading" | "success" | "error" }) {
return (
<Switch.Root>
<Switch.Case condition={status === "loading"}>
<Spinner />
</Switch.Case>
<Switch.Case condition={status === "success"}>
<SuccessPanel />
</Switch.Case>
<Switch.Default>
<ErrorPanel />
</Switch.Default>
</Switch.Root>
);
}
Why This Library
Conditional UI in React often degrades into unreadable logic:
// Before — hard to scan, easy to break
{
status === "loading" ? (
<Spinner />
) : status === "success" ? (
<SuccessPanel />
) : (
<ErrorPanel />
);
}
With this library, the same logic becomes declarative and mirrors native JavaScript:
// After — reads like a switch statement
<Switch.Root>
<Switch.Case condition={status === "loading"}>
<Spinner />
</Switch.Case>
<Switch.Case condition={status === "success"}>
<SuccessPanel />
</Switch.Case>
<Switch.Default>
<ErrorPanel />
</Switch.Default>
</Switch.Root>
| Approach | Readability | Composability | Transition Support |
|---|---|---|---|
| Nested ternaries | Low | Poor | Manual |
if / early return |
High | N/A (outside JSX) | Manual |
| Switch component | High | High | Built-in delay API |
Features
- Zero Dependencies — lightweight bundle, no transitive packages
- Declarative API —
Switch.Case,Switch.Default, andSwitch.Layoutmirror familiar patterns - First-Match Semantics — behaves like a native
switch; the first truthy case wins - Layout Wrapper — inject matched content into a parent element (cards, motion containers, etc.)
- Delayed Switches — per-case or global delays for exit/enter animation coordination
- TypeScript First — full type definitions exported
- React 16.8+ — hooks-based, compatible with React 19
Installation
# pnpm (recommended)
pnpm add @hbi-developer/react-switch-component
# npm
npm install @hbi-developer/react-switch-component
# yarn
yarn add @hbi-developer/react-switch-component
Peer dependency: React >=16.8.0
Quick Start
import { Switch } from "@hbi-developer/react-switch-component";
export function AuthGate({ role }: { role: "admin" | "user" | "guest" }) {
return (
<Switch.Root>
<Switch.Case condition={role === "admin"}>
<AdminDashboard />
</Switch.Case>
<Switch.Case condition={role === "user"}>
<UserDashboard />
</Switch.Case>
<Switch.Default>
<GuestLanding />
</Switch.Default>
</Switch.Root>
);
}
Note:
Switchis an alias forSwitch.Root. Use whichever reads better in your codebase.
How It Works
Children parsed once
↓
First matching Switch.Case selected
↓
No match? → Switch.Default (index 0)
↓
Optional delay applied
↓
Switch.Layout wraps output (if provided)
↓
Single branch rendered to DOM
Evaluation rules:
- Cases are evaluated top to bottom; the first
condition={true}wins. - If no case matches,
Switch.Defaultis rendered. - Only one branch mounts at a time — no hidden siblings in the tree.
delaydefers the index change, keeping the previous branch visible until the timer completes.
Examples
Custom Layout Wrapper
Use Switch.Layout to wrap matched content in a container — ideal for shared styles or animation wrappers.
<Switch.Root>
<Switch.Layout withDefault={true}>
<article className="panel" />
</Switch.Layout>
<Switch.Case condition={isAdmin}>
<AdminPanel />
</Switch.Case>
<Switch.Default>
<UserPanel />
</Switch.Default>
</Switch.Root>
The child of Switch.Layout must be a single React element. Matched case content is injected as its children.
withDefault |
Behavior |
|---|---|
false (default) |
Layout wraps matched cases only |
true |
Layout also wraps Switch.Default content |
Global Delay
Apply a uniform delay before any branch switch — useful when coordinating with CSS transitions.
<Switch.Root delay={300}>
<Switch.Case condition={status === "loading"}>
<LoadingSpinner />
</Switch.Case>
<Switch.Case condition={status === "success"}>
<DataView />
</Switch.Case>
</Switch.Root>
Per-Case Delay
Pass a record to set delays per branch index:
| Index | Target |
|---|---|
0 |
Switch.Default |
1, 2, … |
Switch.Case in order of appearance |
<Switch.Root delay={{ 0: 0, 1: 200, 2: 500 }}>
<Switch.Case condition={status === "success"}>
<SuccessMessage />
</Switch.Case>
<Switch.Case condition={status === "error"}>
<ErrorMessage />
</Switch.Case>
<Switch.Default>
<IdleState />
</Switch.Default>
</Switch.Root>
Invalid delay keys (out of range or non-numeric) throw at runtime with a descriptive error.
API Reference
Switch / Switch.Root
The root container. Accepts cases, an optional default, and an optional layout.
| Prop | Type | Default | Description |
|---|---|---|---|
children |
ReactNode |
— | Switch.Case, Switch.Default, and optionally Switch.Layout |
delay |
number | Record<number, number> |
0 |
Delay in milliseconds before switching branches |
Switch.Case
Renders its children when condition is truthy and no earlier case has matched.
| Prop | Type | Description |
|---|---|---|
condition |
boolean |
When true, this case is a candidate for rendering |
children |
ReactNode |
Content to render when this case is active |
Switch.Default
Fallback branch when no Switch.Case matches.
| Prop | Type | Description |
|---|---|---|
children |
ReactNode |
Fallback content |
Switch.Layout
Optional wrapper applied around the active branch output.
| Prop | Type | Default | Description |
|---|---|---|---|
children |
ReactElement |
— | Wrapper element that receives matched content as children |
withDefault |
boolean |
false |
When true, also wraps Switch.Default output |
Exported Types
import {
Switch,
type SwitchRootProps,
type SwitchCaseProps,
type SwitchDefaultProps,
type SwitchLayoutProps,
} from "@hbi-developer/react-switch-component";
Development
# Clone
git clone https://github.com/HBI-Developer/react-switch-component.git
cd react-switch-component
# Install
pnpm install
# Build (outputs to dist/)
pnpm run build
The package builds with TypeScript (tsc) and publishes only the dist/ directory.
Contributing
Contributions are welcome. For bugs and feature requests, open an issue. For code changes:
git checkout -b feat/your-feature
pnpm run build
git commit -m "feat: describe your change"
git push origin feat/your-feature
Then open a pull request against main.
License
Support
- Issues: github.com/HBI-Developer/react-switch-component/issues
- npm: @hbi-developer/react-switch-component
Declarative conditional rendering — as simple as switch, as native as React.