FezVrasta/popper.js

View on GitHub
website/pages/docs/custom-hooks.mdx

Summary

Maintainability
Test Coverage
<PageCard>

# Custom Hooks

You can build your own custom Hook to perform unique logic that
is not currently exported by the library.

<ShowFor packages={['react-dom']}>

<PackageLimited>@floating-ui/react only</PackageLimited>

</ShowFor>

</PageCard>

The Hooks exported by the library essentially just return HTML
props (`onClick{:.keyword}`, `aria-describedby{:.keyword}`, etc.)
inside a prop getter key, which get merged. You can do the same
thing.

<Notice>
  The library is fully tree-shakeable, so we can add new Hooks
  for specific commonly requested features. If you have ideas for
  new Hooks or functionality, don't hesitate to open a new issue
  or discussion on the [GitHub
  repo](https://github.com/floating-ui/floating-ui)!
</Notice>

```ts
const useCustomLogic = (
  context: FloatingContext,
): ElementProps => {
  const referenceProps = useMemo(
    () => ({
      // React.HTMLProps
      onClick: () => console.log('clicked'),
    }),
    [],
  );
  const floatingProps = useMemo(
    () => ({
      // React.HTMLProps
    }),
    [],
  );
  const itemProps = useMemo(
    () => ({
      // React.HTMLProps
    }),
    [],
  );

  // All 3 of these properties are optional.
  return useMemo(
    () => ({
      reference: referenceProps,
      floating: floatingProps,
      item: itemProps,
    }),
    [referenceProps, floatingProps, itemProps],
  );
};
```

## Communicating between Hooks

Interaction Hooks are decoupled, so passing the shared context
object as a first argument is how they communicate with each
other.

It has an event emitter attached:

```js
const {context} = useFloating();

useEffect(() => {
  const handleEvent = () => {};
  context.events.on('name', handleEvent);
  return () => {
    context.events.off('name', handleEvent);
  };
}, [context.events]);

return (
  <div
    onClick={() => {
      context.events.emit('name', {foo: 'bar'});
    }}
  />
);
```

And also a mutable ref to pass state variables around Hooks:

```js
const {context} = useFloating();

useEffect(() => {
  context.dataRef.current.foo = 'bar';
}, [context]);
```