Search code examples
reactjssemantic-uistyled-componentssemantic-ui-react

Error Cannot read property 'left' of undefined in React Semantic UI Popup with Styled Component


I have a styled component like such:

import styled from 'styled-components';
const TagIcon = styled(Icon).attrs({
  name: 'tag',
})`
  cursor: pointer;
  font-size: 14px !important;
`

If I use this in a semantic-ui-react layout, it works fine in most cases. However, if I use it as a trigger for a SUI Popup component, it causes a crash:

<Popup content="Test Popup" trigger={<TagIcon />} />
Load Page = ... Unhandled Rejection (TypeError): Cannot read property 'left' of undefined
getBoundingClientRect
src/utils/getBoundingClientRect.js:38
  35 | catch(e){}
  36 | 
  37 | const result = {
> 38 |   left: rect.left,
     | ^  39 |   top: rect.top,
  40 |   width: rect.right - rect.left,
  41 |   height: rect.bottom - rect.top,
...
Popper.update$$1
src/index.js:94
  91 | // We can't use class properties because they don't get listed in the
  92 | // class prototype and break stuff like Sinon stubs
  93 | update() {
> 94 |   return update.call(this);
     | ^  95 | }
  96 | destroy() {
  97 |   return destroy.call(this);

If I replace the "TagIcon" styled component with an equivalent(ish) component, it works fine:

<Popup content="Test Popup" trigger={<Icon name="tag">} />

Anyone come across this and have a solution? I'm not sure which git project to report this in if it's an issue, because it seems that there's probably just a conflict with how things are done under the hood between styled components and semantic-ui-react (or possibly also semantic-ui).


Solution

  • I had the same problem and debuged it for a few hours, after finally discovering that its actually simple to solve! The problem is that for some reason popper.js is not receiving the DOM ref to calculate the left/top/width/height, so you need to pass it down "manually" using forwardRef and ref, example:

    // Your Icon component 
    const Icon = forwardRef(
      (props, ref) => (
        <img
          src={props.url}
          ref={ref}
        />
      )
    );
    

    After that just use it normally:

    const TagIcon = styled(Icon)`
      width: 40px;
    `
    
    <Popup content="Test Popup" trigger={<TagIcon url="https://test-image.com">} />
    

    I hope it helps someone!