npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@glhrmoura/react-conditional

v0.10.2

Published

Declarative conditional rendering for React with slots, async, permissions, media, timing gates, and hooks

Readme

React Conditional

NPM Version License

Declarative conditional rendering for React with a slots API, helpers, portals, async states, permissions, media queries, feature flags, and hooks.

Documentation

React Conditional: Documentation

Install

yarn add @glhrmoura/react-conditional
npm install @glhrmoura/react-conditional

Portal needs react-dom (peer dependency, optional if you do not use portals). ErrorBoundary uses the React error boundary API. Media reads window.matchMedia on the client.

Usage

Condition

The precedence order is always If → ElseIf → Else, regardless of the children order.

import { Condition, If, Else } from '@glhrmoura/react-conditional';

const App = ({ isLogged }) => (
  <Condition>
    <If case={isLogged}>The user is logged in</If>
    <Else>The user is not logged in</Else>
  </Condition>
);

Switch Matching

when accepts an exact value, an array, a predicate, or extra values via or. An empty Match falls through to the next Match with children. Prefer a generic Switch for typed unions.

import { Switch, Match, Default } from '@glhrmoura/react-conditional';

const App = ({ status }: { status: 'loading' | 'error' | 'failed' | 'success' | 'idle' }) => (
  <Switch value={status}>
    <Match when='loading'>Loading...</Match>
    <Match when='error' or='failed'>Something went wrong</Match>
    <Match when={1} />
    <Match when={2}>Shared branch for fall-through</Match>
    <Match when={(value) => value === 'success'}>Done</Match>
    <Default>Unknown status</Default>
  </Switch>
);

Unless / Show / Guard

import { Unless, Show, Guard, When } from '@glhrmoura/react-conditional';

const App = ({ isLoading, isLogged, user }) => (
  <>
    <Unless case={isLoading}>
      <Content />
    </Unless>
    <Show case={isLogged} fallback={<LoginPrompt />}>
      <Dashboard />
    </Show>
    <Guard when={user} fallback={<Guest />}>
      {() => <Profile name={user.name} />}
    </Guard>
    <When when={user?.isAdmin}>
      <AdminPanel />
    </When>
  </>
);

Either / Toggle

import { Either, Then, Otherwise, Toggle } from '@glhrmoura/react-conditional';

const App = ({ isOn }) => (
  <>
    <Either case={isOn}>
      <Then>On</Then>
      <Otherwise>Off</Otherwise>
    </Either>
    <Toggle case={isOn} on={<OnIcon />} off={<OffIcon />} />
  </>
);

Compare / Includes

import { Compare, Includes } from '@glhrmoura/react-conditional';

const App = ({ age, role }) => (
  <>
    <Compare value={age} gte={18} fallback={<MinorNotice />}>
      <AdultContent />
    </Compare>
    <Includes value={role} list={['admin', 'editor']} fallback={<Forbidden />}>
      <EditorPanel />
    </Includes>
  </>
);

Exists / Empty / Every / Some / Fallback

import { Exists, Empty, Every, Some, Fallback } from '@glhrmoura/react-conditional';

const App = ({ user, items, isLogged, isAdmin, data }) => (
  <>
    <Exists value={user} fallback={<Guest />}>
      {() => <Profile name={user.name} />}
    </Exists>
    <Empty value={items} fallback={<ItemList items={items} />}>
      <EmptyState />
    </Empty>
    <Every cases={[isLogged, isAdmin]} fallback={<Forbidden />}>
      <AdminPanel />
    </Every>
    <Some cases={[isLogged, items.length > 0]}>
      <FeatureBanner />
    </Some>
    <Fallback case={Boolean(data)} fallback={<Spinner />}>
      {() => <View data={data} />}
    </Fallback>
  </>
);

Once / Lazy

Once keeps rendering after the first true case. Lazy mounts children once when case becomes true and only shows them while case stays true.

import { Once, Lazy } from '@glhrmoura/react-conditional';

const App = ({ ready, open }) => (
  <>
    <Once case={ready}>
      {() => <ExpensiveWidget />}
    </Once>
    <Lazy case={open} fallback={null}>
      {() => <HeavyPanel />}
    </Lazy>
  </>
);

Delay / Debounce / Throttle

Delay waits ms before treating a true case as ready (optional msOut for false). Debounce waits until case stays stable for ms. Throttle limits how often the ready value can change.

import { Delay, Debounce, Throttle } from '@glhrmoura/react-conditional';

const App = ({ isLoading, isTyping, isOnline }) => (
  <>
    <Delay case={isLoading} ms={200} fallback={null}>
      <Spinner />
    </Delay>
    <Debounce case={isTyping} ms={300} fallback={<IdleHint />}>
      <LivePreview />
    </Debounce>
    <Throttle case={isOnline} ms={1000} fallback={<OfflineBanner />}>
      <OnlineBadge />
    </Throttle>
  </>
);

Portal

import { Portal } from '@glhrmoura/react-conditional';

const App = ({ open }) => (
  <Portal case={open} container={document.body}>
    <Modal />
  </Portal>
);

ErrorBoundary

Catch render errors only when case is true. Pass resetKey to clear the error after a retry.

import { ErrorBoundary } from '@glhrmoura/react-conditional';

const App = ({ enabled }) => (
  <ErrorBoundary
    case={enabled}
    resetKey={enabled}
    fallback={(error) => <ErrorView message={error.message} />}
  >
    <RiskyWidget />
  </ErrorBoundary>
);

Async / Await

source accepts a Promise or a function that returns one. Slots are Pending, Resolved, and Rejected. Await is an alias of Async.

import { Async, Await, Pending, Resolved, Rejected } from '@glhrmoura/react-conditional';

const App = ({ loadUser }) => (
  <Async source={loadUser}>
    <Pending>Loading...</Pending>
    <Resolved>{(user) => <Profile name={user.name} />}</Resolved>
    <Rejected>{(error) => <ErrorView message={error.message} />}</Rejected>
  </Async>
);

Permission

Render by capability (can) and/or role. Use PermissionProvider to share lists, or pass permissions / roles on the component. mode is every (default) or some.

import { Permission, PermissionProvider } from '@glhrmoura/react-conditional';

const App = ({ user }) => (
  <PermissionProvider permissions={user.permissions} roles={user.roles}>
    <Permission can="edit" fallback={<ReadOnly />}>
      <Editor />
    </Permission>
    <Permission can={['publish', 'delete']} mode="some" role="admin">
      <Moderation />
    </Permission>
  </PermissionProvider>
);

Media

Match a viewport with min and/or max (number as px, or a CSS length). On the server the query does not match.

import { Media } from '@glhrmoura/react-conditional';

const App = () => (
  <Media min={768} fallback={<MobileNav />}>
    <DesktopNav />
  </Media>
);

Feature

Gate UI with when or with a flag name from FeatureProvider.

import { Feature, FeatureProvider } from '@glhrmoura/react-conditional';

const App = ({ flags }) => (
  <FeatureProvider flags={flags}>
    <Feature when={flags.beta} fallback={<StablePanel />}>
      <BetaPanel />
    </Feature>
    <Feature name="checkout-v2">
      <CheckoutV2 />
    </Feature>
  </FeatureProvider>
);

Hooks

import {
  useShow,
  useMatch,
  useExists,
  useEmpty,
  useIncludes,
  useCompare,
  useMedia,
  usePermission,
  useFeature,
  useDelay,
  useDebounce,
  useThrottle,
} from '@glhrmoura/react-conditional';

function usePanelFlags(user, role) {
  const visible = useShow(Boolean(user));
  const isAdmin = useMatch(role, 'admin', ['owner']);
  const hasUser = useExists(user);
  const noItems = useEmpty(user?.items);
  const allowed = useIncludes(role, ['admin', 'editor']);
  const adult = useCompare(user?.age ?? 0, { gte: 18 });
  const desktop = useMedia(768);
  const canEdit = usePermission({ can: 'edit' });
  const beta = useFeature('beta');
  const delayedLoading = useDelay(Boolean(user?.loading), 200);
  const stableSearch = useDebounce(Boolean(user?.searching), 300);
  const throttledOnline = useThrottle(Boolean(user?.online), 1000);
  return {
    visible,
    isAdmin,
    hasUser,
    noItems,
    allowed,
    adult,
    desktop,
    canEdit,
    beta,
    delayedLoading,
    stableSearch,
    throttledOnline,
  };
}

asChild

Show, Guard, Toggle, Compare, Includes, Once, Lazy, Delay, Debounce, Throttle, ErrorBoundary, Permission, Media, and Feature accept asChild to return a single element without an extra fragment wrapper when possible.

Function Children

Pass a function as children for lazy evaluation. Prefer this for heavy trees and to avoid evaluating branches that do not render.

SSR and streaming

Function children help with SSR and React streaming: unevaluated branches stay cold until selected. Portal falls back to inline render when document is unavailable. Once and Lazy use client state (useRef) and should only gate client-only UI. Delay, Debounce, Throttle, Media, and Async also use client effects; Media treats the query as unmatched during SSR.

API Reference

| Export | Role | | --- | --- | | Condition, If, ElseIf, Else | Boolean slot branches | | Switch, Match, Default | Value match, or, fall-through | | Unless, Show, Guard, When | Standalone boolean / truthy checks | | Either, Then, Otherwise, Toggle | Binary branches | | Compare, Includes | Relational / membership checks | | Exists, Empty, Every, Some, Fallback | Nullish, empty, combined cases | | Once, Lazy, Portal | Sticky, cached, and portal render | | Delay, Debounce, Throttle | Timed case gates | | ErrorBoundary | Catch child errors when case is true | | Async, Await, Pending, Resolved, Rejected | Promise pending / success / error | | Permission, PermissionProvider | Capability and role gates | | Media | Viewport min / max | | Feature, FeatureProvider | Feature flags | | useShow, useMatch, useExists, useEmpty, useIncludes, useCompare, useMedia, usePermission, useFeature, useDelay, useDebounce, useThrottle | Hook mirrors |

Development builds warn when Else / ElseIf render outside Condition, or Match / Default render outside Switch.

License

MIT

Copyright (c) Guilherme Moura