Benjamin Lee
Benjamin Lee

Reputation: 1224

How to implement Portal for a dropdown that isn't clipped inside react-virtualized

Thanks for taking a look at my question.

The answer to this question by @bvaughn creator of react virtualized suggests that you can you can use a portal to create a dropdown inside a virtualized list that can overflow its row without getting clipped.

Here's a sandbox where I've tried just adding a portal inside the card. Rather than use @bvaughn's example (in which he confusingly defines and references but does not render the button that should open the portal (I may be I'm missing something here!?)) I used the example from the tajo/react-portal readme. I've also tried the material ui portal and ReactDOM portal with similar results.

If the element inside the portal doesn't have something like position: absolute and top: 0 then it doesn't appear at all. But if we have to give the top value, how do we know what top value to give so it's where we want it relative to the row / button where it was opened... further, if we use absolute positioning, how would make its position update while scrolling? Sounds do-able, but with a considerable amount of boilerplate.

Here you can see in the sandbox the portal is not clipped by adjacent rows, which is desired. But its position is not relative to the button that opened it:

portal not clipping but not being relative

Here's the relevant code from the sandbox in SimpleCard.js

<CardContent>
          <PortalWithState closeOnOutsideClick closeOnEsc>
            {({ openPortal, closePortal, isOpen, portal }) => (
                <React.Fragment>
                  <button onClick={openPortal}>
                    Open Portal
                  </button>
                  {portal(
                    <p style={{top: '0', position: 'absolute', zIndex: 1000, background: 'red', width: '100px', height: '400px'}}>
                      This is a portal
                      <button onClick={closePortal}>Close me!</button>
                    </p>
                  )}
                </React.Fragment>
             )}
            </PortalWithState>
</CardContent>

I explored passing the row into Portal through node (I was hoping it might just match its position), but that makes render inside the specified node defeating the purpose / not solving the clipping problem.

Any help, insight, or experience you can provide is much appreciated!

Upvotes: 0

Views: 4407

Answers (1)

Benjamin Lee
Benjamin Lee

Reputation: 1224

My question was really to make sure there wasn't an obvious pre-built solution I wasn't finding or understanding, which there doesn't seem to be. So I ended up rolling my own solution.

Basically:

relativeToRef.current.getBoundingClientRect()

The above can be used to get the absolute screen position of the in-list menu opener / button you'd like your portal to be positioned relative to and you can position your portal with those coords.

When thinking about this problem at first I thought it would be necessary to mimic the behavior I already had where the menu stays open and moves along with the list when the list scrolls. Not sure how you would do this well in React given that React state updates will always lag behind scroll frames. Anyway, I realized that from a UI perspective, nothing is really lost and maybe something is gained by making the menu / portal disappear on scroll.

Upvotes: 3

Related Questions