mrkeyoor.com_
Wed 23 Sept 00:32 UTC
npmWeb Frontendupdated 22 Sept 2026

react-universal-interface review

react-universal-interface 0.6.2 lets one React data-provider component accept a function child, `render` prop, component prop, existing custom element, or generated higher-order component. It also includes `hookToRenderProp` for exposing a hook through an older render-prop API. The current version's only release change moved `tslib` from a dependency to a peer dependency, so consumers must supply both React and `tslib`. This is compatibility plumbing from the React 16 render-prop and HOC era, not state management or a visual component.

Verdict

react-universal-interface 0.6.2 installed in 1 second with 4 packages and 1 MB in our sandbox, bundled to 7.7 KB gzipped, and had 0 audit findings. Keep it for a published multi-style component contract; do not add it to new React code that can expose one hook or one explicit composition API.

We installed it

Lab card: what happened when we installed react-universal-interfaceScreenshot of react-universal-interface documentation
Install✓ · 1s4 packages on disk · 1 MB
ImportESM import works · require() works · CommonJS package
Browser7.7 KBgzipped (21.8 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does react-universal-interface install cleanly?

Yes. In a fresh container with an empty cache, npm install react-universal-interface finished in 1 seconds, leaving 4 packages and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does react-universal-interface add to a browser bundle?

7.7 KB gzipped (21.8 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does react-universal-interface work with both ESM and CommonJS?

Yes. Both import 'react-universal-interface' and require('react-universal-interface') worked in Node 22 in our run. The package is published as CommonJS.

Does react-universal-interface include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

react-universal-interface or react-powerplug: which should you use?

react-powerplug: Use it when an older render-prop application needs state and logic components rather than only interface normalization. react-universal-interface 0.6.2 installed in 1 second with 4 packages and 1 MB in our sandbox, bundled to 7.7 KB gzipped, and had 0 audit findings.

When should you not use react-universal-interface?

You are designing a new component API. Hooks, Context, or one explicit child convention are easier to type and explain than five interchangeable forms.

API stability3/5The published surface is small: `render`, `createEnhancer`, `hookToRenderProp`, and `UniversalProps`. Version 0.6.2 has remained unchanged since May 2020, so legacy consumers have seen no churn in precedence or prop merging. That quiet history is not a current compatibility promise. The React peer is `*`, the development stack was built around React 16.8-era types, and no release demonstrates the package against React 18 or 19 behavior. A frozen interface can still fail when its host framework changes.
Docs2/5The README returned HTTP 200 and clearly demonstrates function children, a render prop, `comp`, `component`, custom-element injection, HOC creation, and a basic `UniversalProps` type. It does not mention the shipped `hookToRenderProp` export, `tslib` peer requirement introduced by 0.6.2, precedence when several forms coexist, host-element behavior, collision order for cloned props, extra callback arguments, CommonJS packaging, or any current React boundary. Those omissions cover the cases most likely to surprise a maintainer.
Maintenance1/5npm records 0.6.2 on May 29, 2020, and its release commit only moved `tslib` into peer dependencies. GitHub reports an unarchived repository last pushed on December 9, 2024, with 1 open issue or pull request, but no runtime package followed that activity. The repository's Unlicense metadata also has not repaired the unknown license field observed in the installed package. There is no evidence of a current React test matrix, runtime fixes, or an active release cadence.
Ecosystem2/5npm counted 3,373,138 downloads in the latest completed week, but GitHub reports only 39 stars. The package's reach is therefore likely driven by transitive use in older React libraries rather than new direct adoption. Its universal-interface badge and combination of render props, HOCs, and element injection did not become a standard React convention. Hooks and Context now cover new component APIs without this extra layer, while the package remains useful mainly where old downstream call styles cannot be removed.

Use it if

  • An existing library already promises several render-prop, function-child, component-prop, and HOC call styles.
  • A legacy render-prop public API must stay intact while its internal data source moves to a hook.
  • You can test the package against your supported React versions and own an old compatibility layer.
  • The differing prop precedence of each rendering form is already part of the public contract.
Skip it if

Setup reality

We installed react-universal-interface 0.6.2 in 1 second in our fresh Node 22 sandbox. It left 4 packages and 1 MB on disk, and npm audit reported 0 known vulnerabilities. The package has 0 direct dependencies and 2 peers, 144 KB unpacked, bundled TypeScript declarations, and unknown package-license metadata in our check. It is CommonJS without an exports map; require() and ESM import both worked.

React and tslib are wildcard peers. Version 0.6.2 specifically moved tslib out of dependencies, so the consuming application must install it. Wildcards prevent npm from warning when a 2020 package is paired with a much newer React build. There is no provider, config file, CSS, or initialization step. The declarations were built with older TypeScript and React-era types, so verify them under the application's compiler settings.

The render helper follows precedence rules that are easy to miss. A defined children value wins over the render prop; a function child receives data and extra arguments. comp wins over component. Component forms receive the data object as props, not every provider prop. A custom React element is cloned with data merged over same-named existing props, while a host element such as <div> is returned without that injection.

Our browser build measured 21.8 KB minified and 7.7 KB gzipped for a full-package import. hookToRenderProp is shipped but absent from the README: without a mapper it passes the wrapper's entire props object as the hook's first argument. Zero-argument and positional hooks need a mapping function that returns an array. The library can preserve an old public contract, but adding it to new app code creates more composition paths without adding new React capability.

Patterns

Serve a function child support-function-child

import { render } from 'react-universal-interface';

function MousePosition(props) {
  return render(props, { x: 20, y: 40 });
}

<MousePosition>{({ x, y }) => <output>{x}, {y}</output>}</MousePosition>

A function in `children` wins over `render`; supplying both produces a development warning and still chooses `children`.

Serve a render callback support-render-prop

<MousePosition
  render={({ x, y }) => <output>{x}, {y}</output>}
/>

The `render` prop is considered only when `children` is `undefined`; even non-function child content takes precedence.

Render a supplied component support-component-prop

const PositionLabel = ({ x, y }) => <output>{x}, {y}</output>;
<MousePosition component={PositionLabel} />;

The component receives the provider's data object as props. Other props passed to `MousePosition` are not forwarded by the helper.

Use the shorter component alias use-comp-alias

<MousePosition comp={PositionLabel} />;

`comp` is an alias for `component` and takes priority when both props are present, which can conceal a caller mistake.

Clone a custom child with data inject-custom-element

const PositionLabel = ({ x, y, tone }) => (
  <output data-tone={tone}>{x}, {y}</output>
);

<MousePosition>
  <PositionLabel x={0} y={0} tone="quiet" />
</MousePosition>

Provider data is merged after existing element props, so its `x` and `y` values overwrite the child's 2 supplied values.

Pass actions after provider data pass-extra-callback-arguments

function Counter(props) {
  return render(props, { count: 2 }, { increment: () => {} });
}

<Counter>{({ count }, { increment }) => (
  <button onClick={increment}>{count}</button>
)}</Counter>

Only function-child and render callbacks receive extra positional arguments; component and cloned-element forms receive the data object alone.

Put provider data under one prop create-named-enhancer

const withMouse = createEnhancer(MousePosition, 'mouse');
const Label = ({ mouse }) => <output>{mouse.x}, {mouse.y}</output>;
const LabelWithMouse = withMouse(Label);

A prop name nests the provider result under that name while preserving the wrapped component's ordinary props beside it.

Merge provider fields into wrapped props create-spread-enhancer

const withMouseProps = createEnhancer(MousePosition);
const Enhanced = withMouseProps(({ x, y, prefix }) => (
  <output>{prefix}: {x}, {y}</output>
));

Without a name, provider data is spread first and original component props are spread later, so original props win collisions.

Adapt a zero-argument hook wrap-zero-argument-hook

const OnlineStatus = hookToRenderProp(useOnlineStatus, () => []);

<OnlineStatus>
  {({ online }) => <span>{online ? 'online' : 'offline'}</span>}
</OnlineStatus>

Return an empty array for a zero-argument hook; the default mapper would pass the wrapper's full props object as 1 argument.

Map wrapper props into hook arguments map-hook-arguments

const User = hookToRenderProp(
  useUser,
  (props) => [props.userId]
);

<User userId="42" render={(user) => <strong>{user.name}</strong>} />

The mapping callback must return an array because version 0.6.2 spreads its entries as positional hook arguments.

Alternatives

PackageRegistryPick it when
react-powerplugnpmUse it when an older render-prop application needs state and logic components rather than only interface normalization.
recomposenpmUse it only when maintaining an existing HOC-heavy React codebase already committed to its helper vocabulary.
react-usenpmUse a hook collection when reusable behavior can be exposed directly to modern function components.

More web frontend guides

postcss · react · react-dom · tailwindcss · htmlparser2 · tailwind-merge · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.