Keep tooltip open while hovering over tooltip (rather than closing when leaving trigger)
linden-dg opened this issue · comments
Is your feature request related to a problem? Please describe.
I've created a navigation sidebar that, when you hover over the icon, displays a tooltip with the label for that route. I've got the tooltip working well, but on user testing, some of my users are trying to click on the tooltip rather than the icon.
Because I'm using useHover [const [isOpen, hoverProps] = useHover({ delayEnter: 100, delayLeave: 200 });
] the tooltip closes as the user mouseLeave
's off the triggering element and tries to click the tooltip.
Describe the solution you'd like
Some way/logic to stop the delayLeave
from triggering if the tooltip is hovered as well. Basically if the element or tooltip is hovered then keep the tooltip open, otherwise trigger delayLeave
.
Describe alternatives you've considered
Currently I'm bumping up the delayLeave
number to e.g. 500
to keep the tooltip open for longer, but this doesn't look that great from a UX perspective.
I have a similar problem. The transparent part of the arrow overlaps the text and disappears when the tooltip is hovered.
I fix it like this:
<Arrow
{...arrowProps}
style={{
...arrowProps.style,
width:
arrowProps.layerSide === "left" ||
arrowProps.layerSide === "right"
? '8px'
: undefined,
height:
arrowProps.layerSide === "top" ||
arrowProps.layerSide === "bottom" ||
arrowProps.layerSide === "center"
? '8px'
: undefined,
}}
size={8}
/>
Is your feature request related to a problem? Please describe.
I've created a navigation sidebar that, when you hover over the icon, displays a tooltip with the label for that route. I've got the tooltip working well, but on user testing, some of my users are trying to click on the tooltip rather than the icon.Because I'm using useHover [
const [isOpen, hoverProps] = useHover({ delayEnter: 100, delayLeave: 200 });
] the tooltip closes as the usermouseLeave
's off the triggering element and tries to click the tooltip.Describe the solution you'd like
Some way/logic to stop thedelayLeave
from triggering if the tooltip is hovered as well. Basically if the element or tooltip is hovered then keep the tooltip open, otherwise triggerdelayLeave
.Describe alternatives you've considered
Currently I'm bumping up thedelayLeave
number to e.g.500
to keep the tooltip open for longer, but this doesn't look that great from a UX perspective.
Try this:
import React, { useRef } from 'react';
import { Arrow, useHover, useLayer, mergeRefs } from 'react-laag';
type Props = {
title?: string;
};
const TooltipWrapper: React.FC<Props> = ({ children, title }) => {
const ref = useRef<HTMLDivElement>(null);
const [isOver, hoverProps] = useHover({ delayEnter: 100, delayLeave: 200 });
const { renderLayer, triggerProps, layerProps, arrowProps } = useLayer({
isOpen: isOver
});
const mouseLeaveHandler = (event: React.MouseEvent<HTMLSpanElement, MouseEvent>) => {
const { relatedTarget } = event;
if (!(relatedTarget instanceof Element && ref.current?.contains(relatedTarget))) {
hoverProps.onMouseLeave(event);
}
};
return (
<>
{isOver &&
renderLayer(
<div {...layerProps} ref={mergeRefs(layerProps.ref, ref)} onMouseLeave={hoverProps.onMouseLeave}>
{title}
<Arrow {...arrowProps} />
</div>
)}
<span {...triggerProps} {...hoverProps} onMouseLeave={mouseLeaveHandler}>
{children}
</span>
</>
);
};
export default TooltipWrapper;
Seems like such a common use case — would we really have to write that much code to fix it?
Seems like such a common use case — would we really have to write that much code to fix it?
This is just an example of how to work around it before it fixes.
Thanks for submitting this issue!
What I generally do, and here's an example, is to not only spread the hoverProps
on the trigger-element, but also on the layer-element itself. So, from the perspective of useHover()
it doesn't matter where the 'signals' (enter/leave) originated from, so you could attach the hoverProps (onMouseEnter
/ onMouseLeave
) to any elements you'd like.
// minimal example
function Example() {
const [isOver, hoverProps] = useHover({ delayLeave: 100 });
const { renderLayer, triggerProps, layerProps } = useLayer({
isOpen: isOver
});
return (
<>
{isOver &&
renderLayer(
<div {...layerProps} {...hoverProps}>
Layer!
</div>
)}
<button {...triggerProps} {...hoverProps}>
Trigger!
</button>
</>
);
}
Does this help / answers your question?