OnOpenDelay for Popover Component #35793
Replies: 2 comments
-
|
From what I can see, there isn’t currently a built-in If you need an open delay, you could control the |
Beta Was this translation helpful? Give feedback.
-
|
Since Here’s a reusable “delayed hover popover” wrapper: import * as React from 'react';
import {
Popover,
PopoverSurface,
PopoverTrigger,
type PopoverProps,
} from '@fluentui/react-components';
interface DelayedHoverPopoverProps
extends Omit<PopoverProps, 'open' | 'onOpenChange'> {
/** Delay before opening (ms) */
openDelay?: number;
/** Optional: delay before closing (ms). You can also use mouseLeaveDelay on Popover. */
closeDelay?: number;
trigger: React.ReactElement;
children: React.ReactNode;
}
export const DelayedHoverPopover: React.FC<DelayedHoverPopoverProps> = ({
openDelay = 500,
closeDelay = 0,
trigger,
children,
...popoverProps
}) => {
const [open, setOpen] = React.useState(false);
const openTimer = React.useRef<number | undefined>(undefined);
const closeTimer = React.useRef<number | undefined>(undefined);
const clearTimers = () => {
if (openTimer.current) window.clearTimeout(openTimer.current);
if (closeTimer.current) window.clearTimeout(closeTimer.current);
openTimer.current = undefined;
closeTimer.current = undefined;
};
React.useEffect(() => clearTimers, []);
const scheduleOpen = () => {
// Cancel any pending close and schedule open
if (closeTimer.current) window.clearTimeout(closeTimer.current);
if (open) return;
openTimer.current = window.setTimeout(() => {
setOpen(true);
openTimer.current = undefined;
}, openDelay);
};
const scheduleClose = () => {
// Cancel pending open and schedule close
if (openTimer.current) window.clearTimeout(openTimer.current);
if (closeDelay <= 0) {
setOpen(false);
return;
}
closeTimer.current = window.setTimeout(() => {
setOpen(false);
closeTimer.current = undefined;
}, closeDelay);
};
const onOpenChange: PopoverProps['onOpenChange'] = (_e, data) => {
// Keep internal state in sync for non-hover interactions
clearTimers();
setOpen(!!data.open);
};
return (
<Popover
{...popoverProps}
open={open}
onOpenChange={onOpenChange}
// strongly recommended for hover scenarios:
openOnHover
>
<PopoverTrigger disableButtonEnhancement>
{React.cloneElement(trigger, {
onPointerEnter: (e: React.PointerEvent) => {
trigger.props.onPointerEnter?.(e);
scheduleOpen();
},
onPointerLeave: (e: React.PointerEvent) => {
trigger.props.onPointerLeave?.(e);
scheduleClose();
},
onFocus: (e: React.FocusEvent) => {
trigger.props.onFocus?.(e);
// If you want keyboard focus to open immediately, do this:
clearTimers();
setOpen(true);
},
onBlur: (e: React.FocusEvent) => {
trigger.props.onBlur?.(e);
clearTimers();
setOpen(false);
},
})}
</PopoverTrigger>
{/* If there are no interactive items inside, tabIndex={-1} is recommended */}
<PopoverSurface tabIndex={-1}>{children}</PopoverSurface>
</Popover>
);
};Usage: import * as React from 'react';
import { Button } from '@fluentui/react-components';
import { DelayedHoverPopover } from './DelayedHoverPopover';
export const Example = () => (
<DelayedHoverPopover
openDelay={600}
closeDelay={150}
trigger={<Button>Hover me</Button>}
positioning="above"
>
Delayed open content
</DelayedHoverPopover>
);Notes / a11y considerations
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Do you have any guidance on how to add some sort of on open delay for the Popover Component? There is a 'mouseLeaveDelay' prop, but no 'mouseEnterDelay'. Thanks in advance.
Beta Was this translation helpful? Give feedback.
All reactions