Skip to content

useCustomLogic

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

The hooks exported by the library essentially just return HTML props (onClickonClick, aria-describedbyaria-describedby, etc.) inside a prop getter key, which get merged. You can do the same thing.

const useCustomLogic = (
  context: FloatingContext
): ElementProps => {
  // Note: all 3 of these properties are optional.
  return useMemo(
    () => ({
      reference: {
        // React.HTMLProps
        onClick() {
          console.log('clicked!');
        },
      },
      floating: {
        // React.HTMLProps
      },
      item: {
        // React.HTMLProps
      },
    }),
    []
  );
};
const useCustomLogic = (
  context: FloatingContext
): ElementProps => {
  // Note: all 3 of these properties are optional.
  return useMemo(
    () => ({
      reference: {
        // React.HTMLProps
        onClick() {
          console.log('clicked!');
        },
      },
      floating: {
        // React.HTMLProps
      },
      item: {
        // React.HTMLProps
      },
    }),
    []
  );
};

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:

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'});
    }}
  />
);
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:

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