Skip to content
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

Tooltip not placed properly if in modal #130

Closed
maxmatthews opened this issue Jul 6, 2016 · 17 comments
Closed

Tooltip not placed properly if in modal #130

maxmatthews opened this issue Jul 6, 2016 · 17 comments
Labels

Comments

@maxmatthews
Copy link

The tooltip is being positioned on the modal itself instead of the original tooltip (with the red box around it). Any suggestions on how to get this to anchor to the proper component?
screen shot 2016-07-06 at 12 43 56 pm

@wwayne
Copy link
Collaborator

wwayne commented Jul 7, 2016

Do you have any code to show me? you can put the <ReactTooltip /> out of the modal

<div>
  <Modal><i data-tip='tooltip'><i><Modal>
  <ReactTooltip />
<div>

if your modal's z-index higher than the tooltip, you need to use the attribute class to custom tooltip's z-index, and if opening the modal will cause re-render(re-render the modal), you need use ReactTooltip.rebuild() to relocation the tooltip.

@maxmatthews
Copy link
Author

Unfortunately I can't easily move the ReactTooltip outside of the modal because the modal automatically mounts outside the root component. I tried moving the z-index above the modal and placing javascript componentDidMount(){ ReactTooltip.rebuild(); },
in my Modal's contents and had no luck. Let me know if you need more code and I'll minify mine down a bit more. The basic structure is

<Modal>
<h1>Text Here</h1>
<div style={{display: "inline-block"}}>
    <div onMouseOver={this.onMouseOver}>
        {this.state.tooltipContent == "Loading" ?
            <div data-for="top"
                  data-tip={this.state.tooltipContent}
                  className={className}></div> :
            <div>
                <div data-for={this.props.messageID + "|" + this.props.messageName + "|" + randNum}
                      data-tip={this.state.tooltipContent}
                      className={className}></div>
                <ReactTooltip
                    class="tooltipContent"
                    place="right"
                    type="light"
                    effect="solid"
                    ref="tooltip"
                    html={true}
                    id={this.props.messageID + "|" + this.props.messageName + "|" + randNum}/>
            </div>
        }
    </div>
</div>
</Modal>

I'm loading the tooltip content via an AJAX call so my code is a little complex, but it is working everywhere else but the modal. And it pulls the content in for the modal, just doesn't position it properly.
screen shot 2016-07-07 at 3 53 35 pm

@wwayne
Copy link
Collaborator

wwayne commented Jul 11, 2016

@maxmatthews I did some test, can you try componentDidUpdate() { ReactTooltip.rebuild() }? I'm not sure if it would solve your problem

@maxmatthews
Copy link
Author

ReactTooltip.rebuild() doesn't seem to fix the positioning problem. Whether I call it on componentDidUpdate or when I open the modal or on a second delay after I open the modal using setTimeout or even when I call it in the JS Browser console before or after I open the modal, it still is positioned wrong.

@maxmatthews
Copy link
Author

This is the modal I'm using BTW: https://github.com/reactjs/react-modal

@wwayne
Copy link
Collaborator

wwayne commented Jul 12, 2016

@maxmatthews Okay, I did some experiments again using react-modal and some of your code, so here I think you can follow these three steps:

1.Move <ReactTooltip> out of modal

<div>
 <Modal>
    <div onMouseOver={this.onMouseOver}>
       <div data-for={this.state.tooltipContent === 'loading' && 'top' || (this.props.messageID + "|" + this.props.messageName + "|" + randNum)}
             data-tip={this.state.tooltipContent} className={className}></div>
    </div> 
 </Modal>
 <ReactTooltip ... />
</div>

2.Add React.rebuild() when modal open, for me, I wrote it like:

 openModal () {
    this.setState({modalIsOpen: true}, () => {
      ReactTooltip.rebuild()
    });
  }

3.I suppose that you have built a bunch of tooltip for every modal, maybe it doesn't make sense, you can just have one <ReactTooltip /> out of modal, if you have any custom requirement for tooltip, you can use data-attribute on the target element.

The key logic here is, put <ReactTooltip> out of modal, it just like a tooltip control centre, you don't have to bind it with Modal. And when opening modal, call rebuild to let <ReactTooltip /> to re-calculate the position of the new tooltips

@cristiandan
Copy link

I had the same issue today, same library used, and solved it by moving <ReactTooltip> out of the modal. But I didn't have to move the tooltip in the Main Component, but move the ModalDialog one step down in the hierarchy.

Here's my code if anyone needs help:

MainComponent

render() {

      return(
      <div>
          <ModalContainer onClose={this.closeModal}>
               // I had <ModalDialog onClose={this.closeModal}> here, but I moved them in MyCustomModalContent 
              <MyCustomModalContent job={jobs.selectedModalJob} onClose={this.closeModal} onSave={onSave}/>
              // and here </ModalDialog>
          </ModalContainer> : "" }
      </div>
      )

and the MyCustomModalContent code:

render () {

        var tooltips = []

        for (const key in this.state.attributes) {
            tooltips.push(<div key={key}> 
                <ReactTooltip place="bottom" type="dark" effect="float" id={key}>
                    <span>{this.state.attributes[key].description}</span>
                </ReactTooltip>
            </div>);
        }

        return (
           <div>
            <ModalDialog onClose={this.props.onClose}> // I just moved ModalDialog here and that's pretty much all the change I had to do to make it work.
                <div>
                    {job.name}
                    {activeRows}
                    Advanced:
                    {advancedRows}

                    <button onClick={this.onClickSave}>save</button>

                </div>
                </ModalDialog> // I just moved ModalDialog here
                {tooltipsList} // the tooltips are outside ModalDialog although still in MyCustomModalContent 
            </div>
        );
}

Hope it helps.

@maxmatthews
Copy link
Author

maxmatthews commented Jul 12, 2016

Ok, now I feel like a real idiot and must be missing something simple after such a detailed and helpful response. Now no tooltip shows up on hover. Here's my code.

Master = React.createClass({
  openModal(){
    this.setState({
      showModal: true
    }, ()=>{ReactTooltip.rebuild()})
  },
  render() {
   return <div>
    <Modal
      isOpen={this.state.showModal}
      onRequestClose={this.closeModal}
      className="modal"
      overlayClassName="modalOverlay"
      >
      <div className="row">
        <MyModalContent/>
      </div>
    </Modal>
    <ReactTooltip
      class="tooltipContent"
      place="right"
      type="light"
      effect="solid"
      html={true}
      id={"myUniqueID"}/>
  }
  </div>
});

MyModalContent = React.createClass({
  render(){
    return <div>
      Some text and a tooltip
      <div data-for="myUniqueID"
           data-tip="This is the text in the tooltip"
           className="tooltipContent"></div>
    </div>
  }
});

@maxmatthews
Copy link
Author

Well now I really feel like an idiot because I just put my example code in a blank react project and it's working fine. Ignore me for now, going to debug in my master project to figure out what's causing the issue there and then will post back here.

@maxmatthews
Copy link
Author

maxmatthews commented Jul 12, 2016

When I converted my code to example code to post I put the tooltip inside the modal instead of outside of it. The above code (thanks to @wwayne and @cristiandan help) works in the modal. That may be a good misc. note to add to the readme, "If using tooltips inside of react-modal, the <ReactTooltip> must be placed outside the <Modal> but the <div> it's being attached to can be placed inside the modal's content tag. You should also add ReactTooltip.rebuild() to the onAfterOpen prop of the <Modal> component. If the <ReactTooltip> is placed within the <Modal> it may not position properly or show at all."
If you're up for adding that, do you want me to make a pull request?

@wwayne
Copy link
Collaborator

wwayne commented Jul 12, 2016

@maxmatthews Cool, I will add the notes to README since lots of people was stuck in this.

@itsmichaeldiego
Copy link

My problem is that my whole page where I want to place the tooltip is the modal, is there any way to do it without moving it out? @wwayne

@willsmanley
Copy link

@itsmichaeldiego Just wrap the modal in a fragment like this:

<>
   <ReactToolTip/>
   <Modal/>
</>

It is a lot easier than trying to manually override the positioning of the tooltip, plus it doesn't add another layer to your DOM structure.

@antoine-pous
Copy link

Personally i've just created a component which reflect ReactTooltip and it's work fine without rebuild

@matbrady
Copy link

matbrady commented Oct 9, 2020

Worth adding that if you're using react-responsive-modal, you'll want to trigger a rebuild during the onAnimationEnd Modal method.

const Component = () => {
  // rebuild on specific data changes
  useEffect(() => {
    ReactTooltip.rebuild();
  }, [yourData]);
  
  return (
    <>
      <ReactTooltip />
      <Modal onAnimationEnd={() => { // !!! IMPORTANT PART
        ReactTooltip.rebuild();
      }}>
        <p data-tip="tooltip">Etiam porta sem malesuada magna mollis euismod. Donec ullamcorper nulla non metus auctor fringilla.</p>
      </Modal>
    </>
  );
}

@palicko
Copy link

palicko commented Apr 22, 2021

I solved it with Portal wrapper from #268 (which basically moves Tooltip to <body> element) and just increased z-index on the tooltip to be higher than modal.
This way, I didn't have to move Tooltip outside of the modal component.

@brandonwie
Copy link

brandonwie commented Nov 11, 2022

I solve it by calling ReactTooltip.rebuild() inside useEffect after trying all the methods above. I think there's something wrong when finding the reference, so just made sure that ReactTooltip renders after the element that has data-for renders.

Here's an example.

interface TooltipComponentProps
  extends React.HTMLAttributes<HTMLParagraphElement> {
  tooltipProps?: TooltipProps;
  renderWithDataTip?: GetContentFunc;
  dataTip: string;
}

const TooltipComponent: React.FC<TooltipComponentProps> = ({
  id,
  tooltipProps,
  renderWithDataTip,
  dataTip,
  children,
  className,
  ...props
}) => {
  useEffect(() => {
    ReactTooltip.rebuild();
  }, []);

  return (
    <>
      <p className={className} data-tip={dataTip} data-for={id} {...props}>
        {children}
      </p>
      <ReactTooltip
        id={id}
        getContent={renderWithDataTip ? renderWithDataTip : () => dataTip}
        place={tooltipProps?.place || 'right'}
        effect={tooltipProps?.effect || 'solid'}
        {...tooltipProps}
      />
    </>
  );
};

export default TooltipComponent;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants