Skip to content

FloatingDelayGroup

Provides context for a group of floating elements that should share a delaydelay which temporarily becomes 11 ms after the first floating element of the group opens.

This allows higher discovery of floating elements when they have a hover delay (like tooltips) when their reference elements are placed near each other.

import {FloatingDelayGroup} from '@floating-ui/react';
 
function App() {
  return (
    <FloatingDelayGroup delay={{open: 1000, close: 200}}>
      <Tooltip label="One">
        <button>Ref</button>
      </Tooltip>
      <Tooltip label="Two">
        <button>Ref</button>
      </Tooltip>
      <Tooltip label="Three">
        <button>Ref</button>
      </Tooltip>
    </FloatingDelayGroup>
  );
}
import {FloatingDelayGroup} from '@floating-ui/react';
 
function App() {
  return (
    <FloatingDelayGroup delay={{open: 1000, close: 200}}>
      <Tooltip label="One">
        <button>Ref</button>
      </Tooltip>
      <Tooltip label="Two">
        <button>Ref</button>
      </Tooltip>
      <Tooltip label="Three">
        <button>Ref</button>
      </Tooltip>
    </FloatingDelayGroup>
  );
}

Example

Hooks

These hooks are used:

  • useDelayGroupContext()useDelayGroupContext() — accessible due to a <FloatingDelayGroup /><FloatingDelayGroup /> context wrapper, which provides the contextual delay for the group.
  • useDelayGroup()useDelayGroup() — a hook called inside the component.
function Tooltip() {
  const {delay} = useDelayGroupContext();
  const id = useId();
 
  const [isOpen, setIsOpen] = useState(false);
 
  const {context} = useFloating({
    open: isOpen,
    onOpenChange: setIsOpen,
  });
 
  const hover = useHover(context, {
    delay,
  });
 
  const {getReferenceProps, getFloatingProps} = useInteractions([
    hover,
  ]);
 
  useDelayGroup(context, {
    // Must be unique
    id,
  });
 
  // ...
}
function Tooltip() {
  const {delay} = useDelayGroupContext();
  const id = useId();
 
  const [isOpen, setIsOpen] = useState(false);
 
  const {context} = useFloating({
    open: isOpen,
    onOpenChange: setIsOpen,
  });
 
  const hover = useHover(context, {
    delay,
  });
 
  const {getReferenceProps, getFloatingProps} = useInteractions([
    hover,
  ]);
 
  useDelayGroup(context, {
    // Must be unique
    id,
  });
 
  // ...
}

Props

interface Props {
  delay: Delay;
  timeoutMs?: number;
}
interface Props {
  delay: Delay;
  timeoutMs?: number;
}

delay

Required

default: 00

The delay to use for the group.

<FloatingDelayGroup
  // Both open and close
  delay={200}
  // Or, configured individually
  delay={{open: 1000, close: 200}}
>
  {/* ... */}
</FloatingDelayGroup>
<FloatingDelayGroup
  // Both open and close
  delay={200}
  // Or, configured individually
  delay={{open: 1000, close: 200}}
>
  {/* ... */}
</FloatingDelayGroup>

timeoutMs

default: 00

An optional explicit timeout to use for the group, which represents when grouping logic will no longer be active after the close delay completes. This is useful if you want grouping to “last” longer than the close delay, for example if there is no close delay at all.

<FloatingDelayGroup timeoutMs={500}>
  {/* ... */}
</FloatingDelayGroup>
<FloatingDelayGroup timeoutMs={500}>
  {/* ... */}
</FloatingDelayGroup>

Transitions

The isInstantPhaseisInstantPhase boolean determines whether the delay is currently in the instant phase. This allows you to make transitions instant/faster. See useTransitionStyles.

const {currentId, isInstantPhase} = useDelayGroupContext();
const id = useId();
 
useDelayGroup(context, {
  id,
});
 
const instantDuration = 0;
const duration = 200;
 
const {isMounted, styles} = useTransitionStyles(context, {
  duration: isInstantPhase
    ? {
        open: instantDuration,
        // `id` is this component's `id`
        // `currentId` is the current group's `id`
        close: currentId === id ? duration : instantDuration,
      }
    : duration,
  // ...
});
const {currentId, isInstantPhase} = useDelayGroupContext();
const id = useId();
 
useDelayGroup(context, {
  id,
});
 
const instantDuration = 0;
const duration = 200;
 
const {isMounted, styles} = useTransitionStyles(context, {
  duration: isInstantPhase
    ? {
        open: instantDuration,
        // `id` is this component's `id`
        // `currentId` is the current group's `id`
        close: currentId === id ? duration : instantDuration,
      }
    : duration,
  // ...
});