-
Notifications
You must be signed in to change notification settings - Fork 561
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
React components as Tooltip children? #171
Comments
I ran into this today. The underlying component must be able to the ref that Tooltip is cloning onto the child component. I ended up just modifying my functional component to use forwardRef. If not, you might have to go a low-level so that you can use the useTooltip hook and pass the ref using another convention such as For more info on refs check the React docs here: https://reactjs.org/docs/refs-and-the-dom.html#adding-a-ref-to-a-class-component |
@ericchernuka Hmm, this makes sense but I am not sure exactly what I need to do to solve this. Here's the code for my tooltip component: const Tooltip = (props: TypeProps) => {
const {
label,
position = "bottom",
ariaLabel,
children,
zIndex = 1,
qa,
...rest
} = props;
const [trigger, tooltip] = useTooltip({ DEBUG_STYLE: false });
return (
<React.Fragment>
{React.cloneElement(children, trigger)}
<ReachTooltip
{...tooltip}
label={label}
ariaLabel={ariaLabel || label}
position={positions[position]}
zIndex={zIndex}
{...rest}
/>
</React.Fragment>
);
}; I am using the hook, but I am not sure what ref I am supposed to pass where. |
The |
Ah, I see. So, no matter what I do, this will require source changes to the child component (i.e. this will never work with a component that doesn't forward refs?) |
Pretty sure that’s correct. My implementation was broken today until I added ref forwarding. |
Gotcha. Thanks for the help! This is kind of a bummer because we can't control what the consumer of the component passes in, and if they don't pass a component that forwards refs, it will break in a really weird way. |
I ended up solving this by doing something like this: return (
<React.Fragment>
<Box {...trigger}>
{children}
</Box>
<TooltipContainer
{...tooltip}
label={label}
ariaLabel={ariaLabel || label}
position={positions[position]}
zIndex={zIndex}
{...rest}
/>
</React.Fragment>
); Basically wrapping the children of the tooltip in a container that forwards refs (I updated |
This is a major shortcoming, imo. While building a design system, I cannot guarantee that the |
Tooltip needs a ref so it can manage focus, so you need to forward it. If you don’t like that (seems weird, but okay) drop down to the useTooltip hook and spread the return values wherever you need it. But there’s no need to start wrapping for one off situations. Forward Ref is what you want. |
@ryanflorence is there anything in the docs stating that forwardRefs needs to be used? I see a lot of people having the same issue. |
@ryanflorence I've tried doing what you suggested, but it doesn't seem to work on the second example with |
@raunofreiberg Since the tooltip clones its children, you have to ensure you pass all the props onto the underlying component. So in your example, you need to spread the props from |
I just got here after some time of "Why isn't the tooltip showing at my button?!". Turns out it doesn't work on function components at all. I think the docs should totally mention this, as it's pretty severe. |
@brookback Not sure why you're saying it doesn't work, but you may need to wrap your functional component in As an aside, I can make a PR that indicates that the underlying component requires a |
@ericchernuka Sorry – it worked after I found my way here and read instructions on This shows up in the console at Codesandbox (although not for me locally 🤔): So it looks like it's taken care of already. |
What's the proper way to do this? |
@NickyMeuleman I found a way to make this case work, by passing all props to the underlying span element like this: https://codesandbox.io/s/red-forest-5plimb The need for ref forwarding is major usability issue with this library IMO. We'd need to remember this fact every time we want to use a tooltip. I think the docs should definitely mention this |
I haven't been able to find a way to use a class component as a tooltip child yet. Does anyone know a way? Here's a simple demo with a tooltip wrapping a class component, functional component, and a basic HTML element. As you can see, wrapping a class component causes an unhandled exception from within reach-ui. |
Edit: Ohh interesting, looks like you don't even need function Span(props) {
return <span {...props}>{props.children}</span>;
}
function App() {
return (
<>
<div>
<Tooltip label="Bar">
<Span>Hey Span</Span>
</Tooltip>
</div>
</>
);
} https://codesandbox.io/s/optimistic-mclaren-9vrs05?file=/src/index.js I am guessing this is because reach-ui/packages/tooltip/src/index.tsx Lines 357 to 388 in 3f50109
|
This now seems to be an issue with any HTML element or even when trying to use the fix described above. Upon removing Relates to #916 |
Using
@reach/tooltip
, and getting a lot of errors aboutgetBoundingClientRect
being undefined whenever I nest a React component within the tooltip:If I pass just a regular HTML element, it works just fine. But it seems like components should be supported as children, no?
The text was updated successfully, but these errors were encountered: