react-if-vz is a lightweight, declarative conditional-rendering toolkit for React.
It helps you replace deeply nested ternaries and && chains with clear, readable JSX blocks.
Write conditions like logic, read JSX like a story.
- Ifz / If / ElseIf / Else – nested boolean logic
- When / WhenAll / WhenAny / WhenNot – single-line conditions
- Switch / Case / Default – discrete value matching
- Chain API – fluent
Ifz.chain()syntax - Hook API –
useIfz()for logic-first rendering - Debug logging & StrictMode-safe design
- Function children & shared args
- Optional wrapper / className / style per block
- Perfect for dashboards, admin panels, feature flags, and UI with complex branching logic.
Note: Wrappers are applied only when explicitly provided.
classNameandstyledo not trigger auto-wrapping.
npm install react-if-vzimport { Ifz, If, ElseIf, Else } from "react-if-vz";
<Ifz>
<If condition={isAdmin} debug="admin-check">
<p>Welcome Admin</p>
</If>
<ElseIf condition={role === "user"}>
<p>Welcome User</p>
</ElseIf>
<Else>
<p>Welcome Guest</p>
</Else>
</Ifz><Ifz>
<If condition={(x: number) => x > 10} args={[15]}>
{(x) => <div>{x} is large</div>}
</If>
<Else>
{(args) => <div>Fallback: {args[0]}</div>}
</Else>
</Ifz><Ifz>
<If condition={a}>
A
</If>
<ElseIfz>
<If condition={b}>B</If>
<Else>C</Else>
</ElseIfz>
</Ifz><Ifz>
<If
condition={(user: { id: number; role: "admin" | "user" }) =>
user.role === "admin"
}
args={[{ id: 1, role: "admin" }]}
>
{(user) => <div>Admin ID: {user.id}</div>}
</If>
<Else>
{(args) => <div>User role: {args[0].role}</div>}
</Else>
</Ifz><When condition={isLoggedIn()}>
<p>Welcome back!</p>
</When>
<WhenAll conditions={[isAdmin(), hasPermission()]}>
<p>Admin panel</p>
</WhenAll>
<WhenAny conditions={[isAdmin(), isManager()]}>
<p>Dashboard</p>
</WhenAny>
<WhenNot condition={isGuest()}>
<p>Members only</p>
</WhenNot><Switch value={user.role}>
<Case value="admin">
<p>Admin</p>
</Case>
<Case value="user">
<p>User</p>
</Case>
<Default>
<p>Guest</p>
</Default>
</Switch><Switch>
<Case value={() => result === 1}>One</Case>
<Case value={() => result === 2}>Two</Case>
<Default>Other</Default>
</Switch>Ifz.chain({ trace: true })
.when(isAdmin, <Admin />)
.when(isUser, <User />)
.else(<Guest />);- Ifz.chain only supports zero-argument conditions.
const { when, else: otherwise } = useIfz([value]);
return when(v => v > 10, <Big />)
.when(v => v > 5, <Medium />)
.else(<Small />);| Component | Key Props |
|---|---|
| If / ElseIf | condition, children, args, className, style, wrapper, debug |
| Else | children |
| When | condition, children, args |
| Switch | value, children, args |
| Case | value, children, args, className, style, wrapper |
| Default | children, args, className, style |
- Declarative & readable JSX
- No ternary hell
- Works with StrictMode & SSR
- Optional debug tracing
- Tiny, dependency-free core
| Criteria | react-if-vz | react-if | jsx-control-statements |
|---|---|---|---|
| Declarative JSX | ✅ | ✅ | ✅ |
| Native JSX (no compile step) | ✅ | ✅ | ❌ |
| If / Else | ✅ | ✅ | ✅ |
| ElseIf | ✅ | ❌ | ✅ |
| Switch / Case | ✅ | ✅ | ❌ |
| Boolean Switch (no value) | ✅ | ❌ | ❌ |
| Function children | ✅ | ❌ | |
| Shared args | ✅ | ❌ | ❌ |
| TypeScript inference | ✅ Strong | ❌ | |
| Hook API | ✅ useIfz() |
❌ | ❌ |
| Chain / Fluent API | ✅ | ❌ | ❌ |
| Async condition handling | ❌ (by design) | ✅ | ❌ |
| Wrapper control | ✅ Explicit | ❌ Implicit | ❌ |
| Debug / trace | ✅ | ❌ | ❌ |
| StrictMode safe | ✅ | ||
| SSR safe | ✅ | ❌ | |
| Build-time dependency | ❌ | ❌ | ✅ (Babel plugin) |
| Bundle size | 🟢 Small | 🟢 Small | 🟢 Very small |
| Design philosophy | Logic-first | Feature-rich | Template-like |
| Actively evolving | ✅ | ❌ |
react-if-vz
Designed for TypeScript-first applications with complex UI logic, where predictable and explicit render control matters.
react-if
A good fit for scenarios that require async conditions or Promise-based UI flows.
jsx-control-statements
A template-style approach relying on compile-time transforms; less commonly used in modern TypeScript-centric React codebases.
Why not async conditions?
- react-if-vz keeps rendering pure and synchronous by design.
- Async conditions in JSX make renders unpredictable and harder to debug.
- Async logic belongs in hooks or data layers, not in render flow.
- This keeps UI logic explicit, predictable, and TypeScript-friendly.
Async belongs to data, not JSX.
MIT