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

@wwog/react

v1.4.3

Published

A practical React component library providing declarative flow control and common UI utility components to make your React code more concise and readable.

Readme

@wwog/react

A practical React component library providing declarative flow control and common UI utility components to make your React code more concise and readable.

npm version ESM


中文文档

AI-friendly

This library is designed with AI-assisted development in mind — declarative, type-safe, and predictable.

Add use-wwog-react.md to your project so AI coding agents prefer @wwog/react declarative components over hand-rolled patterns:

| Agent | How to add | |---|---| | Cursor | Copy to .cursor/rules/use-wwog-react.mdc or place as .cursorrules | | Windsurf | Copy to .windsurfrules | | GitHub Copilot | Copy to .github/copilot-instructions.md | | Claude Code | Copy to CLAUDE.md | | Cline | Copy to .clinerules/ | | Roo Code | Copy to .roo/rules/ | | CodeGPT | Copy to .codegpt/rules/ | | Continue | Reference via "rules" in .continuerc.json |

Installation

# Using npm
npm install @wwog/react

# Using yarn
yarn add @wwog/react

# Using pnpm
pnpm add @wwog/react

Features

  • ESModule only: Modern module system support
  • Full TypeScript support: Written in TypeScript with complete type definitions
  • Zero dependencies: Only React and React DOM as peer dependencies
  • Declarative flow control: JSX-style conditional rendering and flow control components
  • Utility components: Simple and practical common UI utility components
  • Lightweight and efficient Excellent performance and compact size

Components & Usage

Flow Control Components

<If>

A declarative conditional rendering component, similar to if-else statements but used in JSX.

import { If } from "@wwog/react";

function Example({ count }) {
  return (
    <If condition={count > 10}>
      <If.Then>
        <p>Count is greater than 10</p>
      </If.Then>
      <If.ElseIf condition={count > 5}>
        <p>Count is greater than 5</p>
      </If.ElseIf>
      <If.Else>
        <p>Count is 5 or less</p>
      </If.Else>
    </If>
  );
}

<Switch>, <Case>, <Default>

A declarative and type-safe alternative to JavaScript's switch statement.

import { Switch } from "@wwog/react";

function Example({ status }) {
  return (
    <Switch value={status}>
      <Switch.Case value="loading">
        <Loading />
      </Switch.Case>
      <Switch.Case value="success">
        <Success />
      </Switch.Case>
      <Switch.Case value="error">
        <Error />
      </Switch.Case>
      <Switch.Default>
        <p>Unknown status</p>
      </Switch.Default>
    </Switch>
  );
}

<When> (v1.1.5+)

A concise conditional rendering component supporting multiple logic combinations. More succinct than , suitable for simple conditions.

import { When } from "@wwog/react";

function Example() {
  const isAdmin = useIsAdmin();
  const isLoading = useIsLoading();
  const hasErrors = useHasErrors();

  return (
    <>
      {/* Render when all conditions are true */}
      <When all={[isAdmin, !isLoading]}>
        <AdminPanel />
      </When>

      {/* Render when any condition is true */}
      <When any={[isLoading, hasErrors]} fallback={<ReadyContent />}>
        <LoadingOrErrorMessage />
      </When>

      {/* Render when all conditions are false */}
      <When none={[isAdmin, isLoading]}>
        <RegularUserContent />
      </When>
    </>
  );
}

<True> / <False> (v1.1.6+)

Helper components for simple boolean conditional rendering.

import { True, False } from "@wwog/react";

function Example({ isActive }) {
  return (
    <>
      <True condition={isActive}>
        <p>Active</p>
      </True>
      <False condition={isActive}>
        <p>Inactive</p>
      </False>
    </>
  );
}
  • <True condition={...}>: Renders children when condition is true.
  • <False condition={...}>: Renders children when condition is false.

<Toggle>

A declarative toggle component that switches values among predefined options and passes them to child components via specified props, supporting custom toggle logic.

import { Toggle } from "@wwog/react";

<Toggle
  options={["light", "dark"]}
  render={(value, toggle) => {
    /* xxx */
  }}
/>;
  • options: Array of values to toggle between.
  • index: Initial Options index.
  • next: Custom toggle logic function.
  • render: Render Function.

Utility Components

<ArrayRender>

Efficiently render array data, supports filtering, sorting, and custom rendering. Optimized for performance with minimal loops.

import { ArrayRender } from "@wwog/react";

function UserList({ users }) {
  return (
    <ArrayRender
      items={users}
      filter={(user) => user.active}
      sort={(a, b) => a.name.localeCompare(b.name)}
      renderItem={(user, index) => (
        <div key={user.id}>
          {index + 1}. {user.name}
        </div>
      )}
      renderEmpty={() => <div>No users found</div>}
    />
  );
}
  • items: Array of data to render
  • renderItem: Function to render each item, receives (item, index) as parameters
  • filter: Optional filter function to filter items
  • sort: Optional sort function for array sorting, uses standard comparison function (a, b) => number
  • renderEmpty: Optional function to render content when array is empty

Performance Note: When no sorting is needed, filtering is done during the map loop for optimal performance. When sorting is provided, filtering is applied first, then sorting, to minimize operations.


#### `<Clamp>` (v1.2.14+)

> Removed in v1.3.0. The compatibility problem is too big, the desktop web page works well, h5 has a problem.

A component for displaying text with a fixed number of lines, ellipsis, and optional extra content.

```tsx
import { Clamp } from "@wwog/react";

function Example() {
  return (
    <Clamp
      text="This is a long text that will be truncated with ellipsis..."
      maxLine={2}
      extraContent={<button>See more</button>}
    />
  );
}
  • text: The text content to be displayed.
  • maxLine: Maximum number of lines, defaults to 1.
  • extraContent: Extra content to display at the end of the text, such as a "See more" button.
  • extraHeight: Height of the extra content, defaults to 20.
  • wrapperStyle: Style for the wrapper container.

<Pipe> (v1.1.7+)

A declarative data pipeline component for multi-step data transformation and chaining.

Declarative data processing, replacing nested function calls. Improves code readability and logic clarity. Suitable for data cleaning, formatting, etc.

import { Pipe } from "@wwog/react";

function Example({ users }) {
  return (
    <Pipe
      data={users}
      transform={[
        (data) => data.filter((user) => user.active),
        (data) => data.map((user) => user.name),
      ]}
      render={(names) => <div>{names.join(", ")}</div>}
      fallback={<div>No Data</div>}
    />
  );
}
  • data: Initial data.
  • transform: Array of transformation functions, applied in order.
  • render: Render the final result.
  • fallback: Content to render if result is null/undefined.

<Scope> (v1.1.7+)

Provides a local scope for children, declaratively defines temporary variables, and simplifies complex rendering logic.

Avoids defining temporary state or calculations outside the component. Declaratively defines local variables for better self-containment. Suitable for forms, computation-heavy rendering, etc.

import { Scope } from "@wwog/react";

function Example() {
  return (
    <Scope let={{ count: 1, text: "Hello" }}>
      {({ count, text }) => (
        <div>
          {text} {count}
        </div>
      )}
    </Scope>
  );
}

// Function-style let is supported
<Scope
  let={(props) => ({ total: props.items.length })}
  props={{ items: [1, 2] }}
  fallback={<div>Empty</div>}
>
  {({ total }) => <div>Total: {total}</div>}
</Scope>;
  • let: Object or function defining scope variables.
  • props: Props passed to the let function.
  • children: Render function for scope variables.
  • fallback: Fallback content when empty.

<DateRender> (v1.2.3+)

A declarative component for formatting and rendering dates, simple to use with support for custom formatting.

import { DateRender } from "@wwog/react";

function Example() {
  return (
    <>
      {/* Using default formatting */}
      <DateRender source="2025-05-06">
        {(formatted) => <div>Date: {formatted}</div>}
      </DateRender>

      {/* Using custom formatting */}
      <DateRender
        source={new Date()}
        format={(date) => date.toLocaleDateString("en-US")}
      >
        {(formatted) => <div>Date: {formatted}</div>}
      </DateRender>
    </>
  );
}
  • source: The input date to render (Date object, ISO string, or timestamp).
  • format: Optional function to format the date, defaults to toLocaleString().
  • children: Function to render the formatted date, receives the formatted date as an argument.

<Observer> (v1.3.1+)

A declarative Intersection Observer component for lazy loading, infinite scrolling, and viewport-based interactions.

import { Observer } from "@wwog/react";

function LazyImage({ src, alt }) {
  const [isVisible, setIsVisible] = useState(false);

  return (
    <Observer
      onIntersect={(entry) => {
        if (entry.isIntersecting) {
          setIsVisible(true);
        }
      }}
      threshold={0.1}
      triggerOnce
    >
      <div className="image-container">
        {isVisible ? (
          <img src={src} alt={alt} />
        ) : (
          <div className="placeholder">Loading...</div>
        )}
      </div>
    </Observer>
  );
}

// Infinite scrolling example
function InfiniteList({ items, onLoadMore }) {
  return (
    <div>
      {items.map((item) => (
        <div key={item.id}>{item.content}</div>
      ))}
      <Observer
        onIntersect={(entry) => {
          if (entry.isIntersecting) {
            onLoadMore();
          }
        }}
        rootMargin="100px"
      >
        <div>Loading more...</div>
      </Observer>
    </div>
  );
}
  • onIntersect: Callback function triggered when intersection changes, receives IntersectionObserverEntry as parameter.
  • threshold: Intersection threshold, can be a number (0-1) or array of numbers, defaults to 0.
  • root: Root element for intersection observation, defaults to viewport.
  • rootMargin: Root margin for expanding/shrinking the root's bounding box, defaults to "0px".
  • triggerOnce: Whether to trigger only once, defaults to false.
  • disabled: Whether to disable observation, defaults to false.
  • children: Child elements to observe.
  • className: CSS class name for the wrapper element.
  • style: Inline styles for the wrapper element.

<Repeat> (v1.3.13+)

A declarative repeat-render component, commonly used for skeleton screens and placeholders.

import { Repeat } from "@wwog/react";

function SkeletonList() {
  return (
    <Repeat times={5}>
      {(i) => <SkeletonItem key={i} />}
    </Repeat>
  );
}
  • times: Number of times to repeat. Renders nothing when <= 0.
  • children: Render function receiving the current 0-based index.

<Portal> (v1.3.13+)

A declarative createPortal wrapper that renders children into a specified DOM node. Handles SSR safely by deferring mount until the client is ready.

import { Portal } from "@wwog/react";

// Render into document.body (default)
function Modal({ children }) {
  return <Portal>{children}</Portal>;
}

// Render into a specific element
function Tooltip({ children }) {
  return (
    <Portal to={document.getElementById("overlay-root")}>
      {children}
    </Portal>
  );
}

// Disable portal and render inline
function ConditionalPortal({ usePortal, children }) {
  return <Portal disabled={!usePortal}>{children}</Portal>;
}
  • to: Target DOM element to mount into. Defaults to document.body.
  • disabled: When true, renders children inline without a portal. Defaults to false.
  • children: Child elements to render into the portal.

<Boundary> (v1.3.13+)

A declarative Error Boundary wrapper with render-prop fallback and reset capability.

import { Boundary } from "@wwog/react";

function App() {
  return (
    <Boundary
      fallback={(error, reset) => (
        <div>
          <p>Something went wrong: {error.message}</p>
          <button onClick={reset}>Retry</button>
        </div>
      )}
      onError={(error, info) => reportError(error, info)}
    >
      <RiskyComponent />
    </Boundary>
  );
}
  • fallback: Render function called when an error is caught. Receives (error: Error, reset: () => void).
  • onError: Optional callback for error reporting (e.g. logging to Sentry).
  • children: Child elements to protect.

<FocusTrap> (v1.4.0+)

A focus trap component that constrains keyboard focus cycling to focusable elements within a container, with support for custom key mappings and navigation logic.

import { FocusTrap } from "@wwog/react";

// Default Tab trapping
<FocusTrap>
  <input />
  <button>Save</button>
</FocusTrap>

// Arrow key navigation
<FocusTrap keyMap={{ ArrowDown: "next", ArrowUp: "prev" }}>
  <div>
    <button>Item 1</button>
    <button>Item 2</button>
  </div>
</FocusTrap>

// Cross-list navigation — items from multiple lists
// seamlessly cross in a single focus order
<FocusTrap keyMap={{ ArrowDown: "next", ArrowUp: "prev" }}>
  <div>
    <h4>List A</h4>
    <button>A-1</button>
    <button>A-2</button>
  </div>
  <div>
    <h4>List B</h4>
    <button>B-1</button>
    <button>B-2</button>
  </div>
</FocusTrap>
  • keyMap: Custom key-to-direction mapping. Default { Tab: "next" } (Shift+Tab auto-maps to "prev"). Example: { ArrowDown: "next", ArrowUp: "prev" }.
  • onNavigate: Custom focus resolution — return the element to focus, or null to use default cycling.
  • autoFocus: Auto-focus the first tabbable element on mount.
  • restoreFocus: Restore focus to the previously focused element on unmount.
  • disabled: Temporarily disable the trap.
  • focusableOptions: Options passed to getTabbableElements (e.g. { includeContainer: true }).

<SizeBox>

Create a fixed-size container for layout adjustment and spacing control.

v1.1.8: Fixed SizeBox not working in 'flex' layouts, add classname props

import { SizeBox } from "@wwog/react";

function Layout() {
  return (
    <div>
      <Header />
      {/* Vertical spacing */}
      <SizeBox height={20} />
      <Content />
      {/* Fixed-size container */}
      <SizeBox width={200} height={150}>
        <SideContent />
      </SizeBox>
    </div>
  );
}

<Styles> (v1.2.7+)

Categorically write styles and basic string styles, with built-in functionality similar to clsx for combining type description object values, supporting duplicate class name removal and nesting.

import { Styles } from "@wwog/react";
import clazz from "./index.module.css";

function Example() {
  return (
    <Styles
      className={{
        base: "p-2 bg-white",
        hover: "hover:bg-gray-100",
        active: "active:bg-gray-200",
        focus: "focus:ring-2",
        other: "button",
      }}
    >
      <Styles className={clazz.button}>
        <button>Click me</button>
      </Styles>
    </Styles>
  );
}

You can also use a container wrapper element:

<Styles
  className={{
    base: ["p-2"],
    hover: { "hover:bg-blue-500": true },
  }}
  asWrapper="span"
>
  Content
</Styles>
  • className [string | StylesDescriptor]: Category object for class names, all values in the object will be merged
  • asWrapper [boolean | HTMLElementType]: Whether to generate a wrapper containing all classNames, default is false, pass tag name like 'div' or 'span'
  • children : Only works with a single child element; if there are multiple child elements, please pass asWrapper to write types and avoid ambiguity

hooks

useControlled

  • Applied to states that can be controlled or uncontrolled components

useScreen (v1.3.5+)

Return the current breakpoint name

  • Supports passing in custom breakpoints, defaults to the same breakpoint definitions as TailwindCSS

This hook is implemented based on listening. If useScreen needs to be used multiple times without changing the passed parameters, it is recommended to wrap Context

Development notes: Internally implemented via mediaQuery, it does not listen to a specific breakpoint but is optimized to listen only to the previous and next breakpoints of the current breakpoint for better performance.

utils

Internal functions used by some components, which can also be used if needed

createExternalState (v1.2.9+, useGetter added in v1.2.13)

v1.4.2: Remove transform options v1.3.14: Breaking: use() renamed to useState() for React 19 compiler compatibility (the compiler requires hook names to start with use; the old use method was misidentified as a non-hook) v1.2.21: Refactor the API to move sideeffects into options and enhance support for the transform interface v1.2.13: add useGetter Breaking: sideEffect replaced by onSet and onChange for clearer callback semantics

Migration (v1.3.13 → v1.3.14)

- const [theme, setTheme] = themeState.use();
+ const [theme, setTheme] = themeState.useState();

useGetter() is unchanged.

A lightweight external state management utility that allows you to create and manage state outside the React component tree while maintaining perfect integration with components.

createStorageState (v1.3.2+)

Extends from createExternalState and uses storage to persist state, supports localStorage and sessionStorage

  • createStorageState<T>(key, initialState, options?): Creates persisted state
    • options.onSet: Invoked on every set() (storage write happens first, then the user callback)
    • options.onChange: Invoked only when the value actually changes
    • options.storageType: 'local' | 'session', defaults to 'local'
import { createExternalState } from "@wwog/react";

// Create a global theme state
const themeState = createExternalState("light", {
  onChange: (newTheme, oldTheme) => {
    console.log(`Theme changed from ${oldTheme} to ${newTheme}`);
  },
});

// Get or modify state from anywhere
console.log(themeState.get()); // 'light'
themeState.set("dark");

// Use the state in components
function ThemeConsumer() {
  const [theme, setTheme] = themeState.useState();

  return (
    <div className={theme}>
      Current theme: {theme}
      <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
        Toggle theme
      </button>
    </div>
  );
}

// For read-only access (v1.2.13+)
function ReadOnlyThemeConsumer() {
  const theme = themeState.useGetter();

  return <div>Current theme is: {theme}</div>;
}
  • createExternalState<T>(initialState, options?): Creates a state accessible outside components

    • initialState: Initial state value
    • options.onSet: Optional callback invoked on every set() call, even when the value is unchanged
    • options.onChange: Optional callback invoked only when the stored value actually changes (compared via Object.is)
    • Returns an object with methods:
      • get(): Get the current state value
      • set(newState): Update the state value
      • useState(): React Hook, returns [state, setState] for using this state in components (same return shape as React useState)
      • useGetter(): React Hook that only returns the state value, useful when you only need to read the state

    Use cases:

  • Global state management (themes, user settings, etc.)

  • Cross-component communication

  • Reactive state in services or utility classes

  • Sharing state with non-React code

formatDate

A relatively standard date formatting function

childrenLoop

Interruptible child node traversal, enabling some branch processes to have ultimate performance

Counter

Incrementally class

safePromiseTry (v1.2.10+)

Support Promise.try Use Promise.try, otherwise use internal implementation

cx (v1.2.5+)

An efficient CSS class name merging utility function, similar to clsx or classnames, but automatically removes duplicate class names.

import { cx } from "@wwog/react";

function Example({ isActive, isDisabled }) {
  return (
    <div
      className={cx("base-class", ["array-class-1", "array-class-2"], {
        "active-class": isActive,
        "disabled-class": isDisabled,
      })}
    >
      Content
    </div>
  );
}

Supports various parameter types:

  • String: "class1 class2"
  • String array: ["class1", "class2"]
  • Object: { "class1": true, "class2": false }
  • Any combination of the above types

License