content/docs/api/react-utils.mdx
@udecode/react-utils provides small React primitives used across Plate UI packages. It is also re-exported from platejs/react and @udecode/cn.
npm install @udecode/react-utils
Use direct imports in shared UI packages. Use platejs/react when you are already inside a Plate app surface.
| Component | Renders | Notes |
|---|---|---|
PortalBody | ReactDOM.createPortal(children, element ?? document.body) | Returns children directly when no DOM container is available. |
Box | Slot-aware div | Created with createSlotComponent('div'). Supports as and asChild. |
Text | Slot-aware span | Created with createSlotComponent('span'). Supports as and asChild. |
MemoizedChildren | React.memo(({ children }) => <>{children}</>) | Prevents child-only rerenders when parent props are stable. |
import { PortalBody } from '@udecode/react-utils';
export function BodyOverlay() {
return (
<PortalBody>
<div role="status">Saving</div>
</PortalBody>
);
}
Use primitive factories when a component needs asChild, composed refs, hook-provided props, or hook-provided state.
createPrimitiveComponent merges hook class names before consumer class names, merges hook style before consumer style, composes forwarded refs with hook refs, and returns null when hidden is true unless asChild is set.
| API | Type | Behavior |
|---|---|---|
composeRefs(...refs) | (...refs) => (node) => cleanup? | Sets callback refs and ref objects to the same node. If refs return cleanup functions, the composed ref returns a cleanup. |
useComposedRef(...refs) | (...refs) => refCallback | Memoized composeRefs callback. |
useStableFn(fn, deps?) | (fn, deps = []) => stableFn | Returns a stable function that calls the latest fn. |
useStableMemo(producer, deps?) | (producer, deps?) => value | Stores a produced value in state and updates it in a layout effect. |
useEffectOnce(effect, deps) | (effect, deps) => void | Runs the effect on first render and again when the dependency values change. |
useIsomorphicLayoutEffect | React.useLayoutEffect | React.useEffect | Uses layout effect in the browser and effect during SSR. |
import * as React from 'react';
import { useComposedRef } from '@udecode/react-utils';
export const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
(props, ref) => {
const localRef = React.useRef<HTMLInputElement>(null);
const composedRef = useComposedRef(ref, localRef);
return <input ref={composedRef} {...props} />;
}
);
useOnClickOutside returns a callback ref unless you pass explicit refs.
| API | Type | Behavior |
|---|---|---|
useMemoizedSelector(selector, deps, equalityFn?) | (selector, deps, equalityFn?) => value | Re-renders only when the selector result changes. The default equality is strict equality. |
composeEventHandlers(original, next, options?) | (event) => void | Calls original, then calls next unless event.defaultPrevented and checkForDefaultPrevented is true. |
import { withProviders } from '@udecode/react-utils';
const ThemeProvider = ({ children }: { children: React.ReactNode }) => (
<div data-theme="dark">{children}</div>
);
const Page = () => <main>Docs</main>;
export const ThemedPage = withProviders(ThemeProvider)(Page);