Example of using arrow in Popper component of material-ui
Asked Answered
C

4

22

There is playground example on Popper component page of material-ui. To add arrow they use arrowRef. Please explain me where do they get it from?

Calbert answered 14/8, 2019 at 18:40 Comment(1)
Did you get arrowRef from where , If yes please feel free to reply as am troubling with same issuePlankton
F
4

For anyone else that needs it, the OP is asking about Material-UI Poppers.

Dmitriy,

Think of React Refs as a variable that always references the element (if rendered) OUTSIDE of the DOM. React best practices are typically to stay out of the DOM if at all possible. There are of course exceptions to this, but it's the rule of thumb.

In this particular instance, it appears that they are creating an element elsewhere and referencing it using the ref so that it can be utilized by the Popper. I found an example of this here. It's a little hard to read through, but the jist is that he creates a span and styles it how he wants to be applied.

Fauna answered 14/8, 2019 at 18:58 Comment(5)
I’ve seen this style for arrow in several places before, but I couldn’t expect that it is arrow by itself!! I mean that it’s totally unexpected effect (at least for me) , that setting zero height and width and non-zero borders brings an arrow. Wouldn’t you be so kind explaining, why they use && at the beginning of tagged template literal for StyledPopper in your example code?Calbert
I've actually never seen it before, but it's apparently a way to bump the classNames up for overwriting inline styles. medium.com/@pitipatdop/…Fauna
I’ve found explanation in styled-components FAQ. The aim is to rise rule specificity. Every & becomes a generated classname selector.Calbert
One more question. What is the reason for &:before clause in aforementioned example? I’ve tried to change rules under this selector in playground- nothing changed.Calbert
Looking at the DOM, I don't see any of those :before pseudo selectors applied. It seems you could safely not use that part of the style.Fauna
O
18

You can find the source code of the Material UI Popper "Scroll Playgroud" example here: https://github.com/mui-org/material-ui/blob/4f2a07e140c954b478a6670c009c23a59ec3e2d4/docs/src/pages/components/popper/ScrollPlayground.js

As you can see, there is some extra styling that you will need to add to your app to display the arrow correctly, because it's not included in the Material UI library itself.

Odyssey answered 10/7, 2020 at 15:34 Comment(1)
Best answer (although I would have pointed to the master branch instead). Since MUI is using Popper.js, also check out the Arrow tutorial on their website.Noahnoak
D
16

For others looking for a concrete, reusable component that is simple to use like Tooltip but has a more interactive nature like Popper or Popover you can lift and shift the RichTooltip component from the following sandbox I created - it's typescript too. Hope this helps the next person and hides the complexity of arrows for you.

https://codesandbox.io/s/popper-with-arrow-58jhe

Deodorize answered 24/9, 2020 at 5:29 Comment(6)
This may not be the acceptable answer, but it's a VERY good solution, with workable codes and demonstration in CodeSandbox. Thanks for the great demo!Folkestone
Appriciate your efforts. Thanks!Dunnock
Thanks @Matt. Is there a way you can modify this for v5?Weihs
Fantastic, thank you for sharing this!Novitiate
Very useful and a time saver. NPM repo?Finnougric
This should be part of mui's core componentsSubsellium
F
4

For anyone else that needs it, the OP is asking about Material-UI Poppers.

Dmitriy,

Think of React Refs as a variable that always references the element (if rendered) OUTSIDE of the DOM. React best practices are typically to stay out of the DOM if at all possible. There are of course exceptions to this, but it's the rule of thumb.

In this particular instance, it appears that they are creating an element elsewhere and referencing it using the ref so that it can be utilized by the Popper. I found an example of this here. It's a little hard to read through, but the jist is that he creates a span and styles it how he wants to be applied.

Fauna answered 14/8, 2019 at 18:58 Comment(5)
I’ve seen this style for arrow in several places before, but I couldn’t expect that it is arrow by itself!! I mean that it’s totally unexpected effect (at least for me) , that setting zero height and width and non-zero borders brings an arrow. Wouldn’t you be so kind explaining, why they use && at the beginning of tagged template literal for StyledPopper in your example code?Calbert
I've actually never seen it before, but it's apparently a way to bump the classNames up for overwriting inline styles. medium.com/@pitipatdop/…Fauna
I’ve found explanation in styled-components FAQ. The aim is to rise rule specificity. Every & becomes a generated classname selector.Calbert
One more question. What is the reason for &:before clause in aforementioned example? I’ve tried to change rules under this selector in playground- nothing changed.Calbert
Looking at the DOM, I don't see any of those :before pseudo selectors applied. It seems you could safely not use that part of the style.Fauna
O
2
MUI v5
  1. Add the modifiers for arrow. Make sure a proper ref is provided.

const [arrowRef, setArrowRef] = useState(null);

<Popper 
    modifiers={[
      {
       name: 'arrow',
       enabled: true,
       options: {
         element: arrowRef,
       }
      }
    ]}
>
<Box component="span" className="arrow" ref={setArrowRef} />
</Popper>
  1. Add arrow specific styles.
const styles = {
    arrow: {
        position: 'absolute',
        fontSize: 7,
        width: '3em',
        height: '3em',
        '&::before': {
          content: '""',
          margin: 'auto',
          display: 'block',
          width: 0,
          height: 0,
          borderStyle: 'solid',
        },
    }
};

<Box component="span" className="arrow" ref={setArrowRef} sx={styles.arrow}/>
  1. Add styles for making CSS triangles used by arrow. Make a styled Popper, as Popper doesn't support sx prop.

const StyledPopper = styled(Popper)(({ theme }) => ({ // You can replace with `PopperUnstyled` for lower bundle size.
  zIndex: 1,
  maxWidth: '375px',
  width: '100%',
  '&[data-popper-placement*="bottom"] .arrow': {
    top: 0,
    left: 0,
    marginTop: '-0.9em',
    width: '3em',
    height: '1em',
    '&::before': {
      borderWidth: '0 1em 1em 1em',
      borderColor: `transparent transparent ${theme.palette.background.paper} transparent`,
    },
  },
  '&[data-popper-placement*="top"] .arrow': {
    bottom: 0,
    left: 0,
    marginBottom: '-0.9em',
    width: '3em',
    height: '1em',
    '&::before': {
      borderWidth: '1em 1em 0 1em',
      borderColor: `${theme.palette.background.paper} transparent transparent transparent`,
    },
  },
  '&[data-popper-placement*="right"] .arrow': {
    left: 0,
    marginLeft: '-0.9em',
    height: '3em',
    width: '1em',
    '&::before': {
      borderWidth: '1em 1em 1em 0',
      borderColor: `transparent ${theme.palette.background.paper} transparent transparent`,
    },
  },
  '&[data-popper-placement*="left"] .arrow': {
    right: 0,
    marginRight: '-0.9em',
    height: '3em',
    width: '1em',
    '&::before': {
      borderWidth: '1em 0 1em 1em',
      borderColor: `transparent transparent transparent ${theme.palette.background.paper}`,
    },
  },
}));

Replace the Popper with the above StyledPopper

<StyledPopper 
    modifiers={[
         {
          name: 'arrow',
          enabled: true,
          options: {
            element: arrowRef,
         }
    ]}
>
<Box component="span" className="arrow" ref={setArrowRef} />
// rest of the code
</StyledPopper>
Officialdom answered 30/6, 2022 at 6:47 Comment(1)
This worked for me.Hahnert

© 2022 - 2024 — McMap. All rights reserved.