OnOpenDelay for Popover Component #35793
Unanswered
LauraAlspaugh
asked this question in
Q&A
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 |
0 replies
|
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
|
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
All reactions