Skip to main content
The @wordpress/compose package provides a collection of handy React Hooks and Higher Order Components (HOCs) you can use to wrap your WordPress components and provide basic features like state management, instance IDs, and more.

Installation

Install the package using npm:
npm install @wordpress/compose --save
This package assumes that your code will run in an ES2015+ environment. If you’re using an environment with limited support for such language features, include the polyfill shipped in @wordpress/babel-preset-default.

The compose Function

The compose function is inspired by lodash’s flowRight and allows you to compose any number of functions. It executes the last function first, then sequentially moves back through the previous functions, passing the result upward. Think of it as layering functions - each function wraps the result of the next:
const compose = ( f, g ) => x => f( g( x ) );

Example: Using compose

Here’s how you can use compose to combine multiple HOCs:
import { compose } from '@wordpress/compose';
import { withSelect, withDispatch } from '@wordpress/data';

const applyWithSelect = withSelect( ( select, ownProps ) => {
	return doSomething( select, ownProps );
} );

const applyWithDispatch = withDispatch( ( dispatch, ownProps ) => {
	return doSomethingElse( dispatch, ownProps );
} );

export default compose(
	withPluginContext,
	applyWithSelect,
	applyWithDispatch
)( PluginSidebarMoreMenuItem );

useInstanceId

Provides a unique instance ID for component instances:
import { useInstanceId } from '@wordpress/compose';

function MyComponent( { prefix = 'field' } ) {
	const id = useInstanceId( MyComponent, prefix );
	return <input id={ id } />;
}

useDebounce

Debounces a function similar to Lodash’s debounce:
import { useDebounce } from '@wordpress/compose';
import { useState, useCallback } from '@wordpress/element';

function SearchInput() {
	const [ searchTerm, setSearchTerm ] = useState( '' );
	
	const debouncedSearch = useDebounce(
		useCallback( ( value ) => {
			// Perform search with value
			console.log( 'Searching for:', value );
		}, [] ),
		500
	);
	
	const handleChange = ( value ) => {
		setSearchTerm( value );
		debouncedSearch( value );
	};
	
	return <input value={ searchTerm } onChange={ ( e ) => handleChange( e.target.value ) } />;
}

useFocusOnMount

Determines focus behavior when an element mounts:
import { useFocusOnMount } from '@wordpress/compose';

function Dialog() {
	const ref = useFocusOnMount();
	return (
		<div ref={ ref }>
			<button>First Button</button>
			<button>Second Button</button>
		</div>
	);
}

useMediaQuery

Runs a media query and returns its value:
import { useMediaQuery } from '@wordpress/compose';

function ResponsiveComponent() {
	const isMobile = useMediaQuery( '(max-width: 768px)' );
	
	return (
		<div>
			{ isMobile ? 'Mobile View' : 'Desktop View' }
		</div>
	);
}

useRefEffect

Effect-like ref callback that allows cleanup:
import { useRefEffect } from '@wordpress/compose';

function ComponentWithEventListener() {
	const ref = useRefEffect(
		( node ) => {
			const handleClick = () => console.log( 'Clicked!' );
			node.addEventListener( 'click', handleClick );
			
			// Return cleanup function
			return () => {
				node.removeEventListener( 'click', handleClick );
			};
		},
		[]
	);
	
	return <div ref={ ref }>Click me!</div>;
}

Essential Hooks

useInstanceId

Generate unique IDs for component instances

useDebounce

Debounce function calls to improve performance

useMediaQuery

Responsive design with media query detection

useFocusOnMount

Control focus behavior when components mount

useRefEffect

Ref callbacks with cleanup capabilities

useResizeObserver

Observe element size changes

useMergeRefs

Combine multiple refs into one callback

usePrevious

Access previous render values

Higher Order Components

withInstanceId

Provides a unique instance ID via props:
import { withInstanceId } from '@wordpress/compose';

function MyComponent( { instanceId } ) {
	return <div id={ `component-${ instanceId }` }>Content</div>;
}

export default withInstanceId( MyComponent );

ifCondition

Renders a component only if a condition is satisfied:
import { ifCondition } from '@wordpress/compose';

const Component = ( { foo } ) => <div>{ foo }</div>;

const ConditionalComponent = ifCondition(
	( { foo } ) => foo.length !== 0
)( Component );

// <ConditionalComponent foo="" /> renders null
// <ConditionalComponent foo="bar" /> renders <div>bar</div>

Utility Functions

createHigherOrderComponent

Creates a higher-order component with a generated display name:
import { createHigherOrderComponent } from '@wordpress/compose';

const withCustomBehavior = createHigherOrderComponent(
	( WrappedComponent ) => {
		return ( props ) => {
			// Add custom behavior
			return <WrappedComponent { ...props } customProp="value" />;
		};
	},
	'withCustomBehavior'
);

debounce

Creates a debounced function:
import { debounce } from '@wordpress/compose';

const debouncedSave = debounce(
	( value ) => {
		// Save value
		console.log( 'Saving:', value );
	},
	500,
	{ leading: false, trailing: true }
);

throttle

Creates a throttled function:
import { throttle } from '@wordpress/compose';

const throttledScroll = throttle(
	() => {
		// Handle scroll
		console.log( 'Scrolling' );
	},
	100
);

Peer Dependencies

This package requires React as a peer dependency:
{
	"peerDependencies": {
		"react": "^18.0.0"
	}
}
Make sure you have React 18.0.0 or higher installed in your project.

API Reference

For complete API documentation of all hooks and HOCs, visit the GitHub repository.

Build docs developers (and LLMs) love