How to make a dropdown menu open below the Appbar using Material-UI?

ReactjsMaterial Ui

Reactjs Problem Overview


I'm new to Material-UI and just started fiddling around with their App bar with Menu example. When toggling the menu dropdown, it opens up over the Appbar itself, whereas I'd like it to open below the Navbar.

From the docs, I understand that this can be done with anchorEl as explained here. But when I implement this to my menu component nothing happens. What is "the right material-UI way" to take care of this?

class Header extends React.Component {
  state = {
    auth: true,
    anchorEl: null,
    anchorOriginVertical: 'bottom',
    anchorOriginHorizontal: 'right',
    transformOriginVertical: 'top',
    transformOriginHorizontal: 'right',
    anchorReference: 'anchorEl',
  };

  handleChange = (event, checked) => {
    this.setState({ auth: checked });
  };

  handleMenu = event => {
    this.setState({ anchorEl: event.currentTarget });
  };

  handleClose = () => {
    this.setState({ anchorEl: null });
  };

  render() {
    const { classes } = this.props;
    const { auth, anchorEl } = this.state;
    const open = Boolean(anchorEl);

    return (
      <div className={classes.root}>
        <AppBar position="static">
          <Toolbar>
            <Typography type="title" color="inherit" className={classes.flex}>
              Title
            </Typography>
            {auth && (
              <div>
                <IconButton
                  aria-owns={open ? 'menu-appbar' : null}
                  aria-haspopup="true"
                  onClick={this.handleMenu}
                  color="contrast"
                >
                  <AccountCircle />
                </IconButton>
                <Menu
                  id="menu-appbar"
                  anchorEl={anchorEl}
                  open={open}
                  onClose={this.handleClose}
                >
                  <MenuItem onClick={this.handleClose}>Profile</MenuItem>
                  <MenuItem onClick={this.handleClose}>My account</MenuItem>
                </Menu>
              </div>
            )}
          </Toolbar>
        </AppBar>
      </div>
    );
  }
}

Reactjs Solutions


Solution 1 - Reactjs

I had a similar issue and the way I got it to work is by setting the properties on the menu itself like this:

  <Menu
    id="menu-appbar"
    anchorEl={anchorEl}
    getContentAnchorEl={null}
    anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
    transformOrigin={{ vertical: "top", horizontal: "center" }}
    open={open}
    onClose={this.handleClose}
    className={props.classes.menu}
  >

I had to put in getContentAnchorEl={null} to get the vertical properties to work, which I eventually learned from this issue https://github.com/mui-org/material-ui/issues/7961 .

Not sure how to do this when using the state to set the properties of the anchor element, but maybe this will get you started.

Solution 2 - Reactjs

This was my solution, hope this will help someone.

<Menu
  open={this.state.openProps}
  anchorEl={this.state.anchorEl}
  onClose={onClose}
  className={classes.styles}
  disableAutoFocusItem
  PaperProps={{
    style: {
      left: '50%',
      transform: 'translateX(-77%) translateY(32%)',
    }
  }}
  MenuListProps={{
    style: {
      padding: 0,
    },
  }}
>

Solution 3 - Reactjs

There is an error in Matheus answer, the type of anchorEl is not boolean, in ReactHooks it would need to be:

  const [menuOpen, setMenuOpen] = useState<boolean>(false);
  const [anchorEl, setAnchorEl] = useState()

  const recordButtonPosition = (event: any) => {
      setAnchorEl(event.currentTarget);
      setMenuOpen(true);
  }

  let closeMenu = () => {
      setMenuOpen(false);
  }

  return (
      <React.Fragment>
          <Button onClick={recordButtonPosition}>
              OPEN MENU
          </Button>
          <Menu
              anchorEl={anchorEl}
              open={menuOpen}
              onClose={closeMenu}>
              <MenuItem onClick={closeMenu}> ExampleMenuItem </MenuItem> 
          </Menu>
      </React.Fragment>
  );

Solution 4 - Reactjs

For me i had issue of jumping effect , after clicking first time .. i had to make keepMounted={false}

and you can get x and y value by adjusting translateX(10px) translateY(50px) from devTool.

enter image description here

                      <div>
                         <Menu
                                    id="simple-menu"
                                    anchorEl={anchorEl}
                                    keepMounted={false}
                                    open={Boolean(anchorEl)}
                                    onClose={this.handleClose}
                                    PaperProps={{
                                        style: {
                                            transform: 'translateX(10px) translateY(50px)',
                                        }
                                    }}
                                >
                                    <MenuItem onClick={this.handleClose}>My Account</MenuItem>
                                    <Divider variant="middle"/>
                                    <MenuItem onClick={this.handleClose}>Logout</MenuItem>
                                </Menu>
                            </div>

Solution 5 - Reactjs

it is because you have not defined the anchor.

The Menu attribute - anchorEl, is responsible for passing the location of the button that called it, not true to say this, but only to be easy to understand.

In this way, you should refer whenever there is a click. I suggest you use the reaction hooks, which makes the component clean.

React Stateful

const [menuOpen, setMenuOpen] = useState(false)
const [anchorEl, setAnchorEl] = useState(false)

const handleClick = (event) => {
const anchorEl = event.currentTarget
this.setState({ ...this.state, menuOpen: !menuOpen , anchorEl })

React Hooks

const [menuOpen, setMenuOpen] = useState(false)
const [anchorEl, setAnchorEl] = useState(false)

const handleClick = (event) => {
setAnchorEl(event.currentTarget)
}

render

return (
 <Menu
   anchorEl={anchorEl}
   open={menuOpen}
   onClose={handleClick }              
 </Menu 
)

Solution 6 - Reactjs

An easy way to achieve that is using useRef hook

  1. Create the ref
  2. insert your ref were you want to show the menu in your case a Div or other
  3. inser the ref in the anchor prop of the menu

enter code here

const inputEl = useRef(null);
<Mycomponent ref={inputEl}/>
<Menu
  id="simple-menu"
  anchorEl={inputEl.current}
  keepMounted
  open={Boolean(anchorEl)}
  onClose={handleClose}
>

for me this is by far the easier way

Solution 7 - Reactjs

In the New Material-ui version 5, I don't understand why this weird thing happens. But it works when I create a separate menu component in the app bar.

import * as React from 'react';
import { useRouter } from 'next/router'
import { Menu, IconButton, } from '@mui/material';
import MenuItem from '@mui/material/MenuItem';
import AccountCircle from '@mui/icons-material/AccountCircle';

export default function AppBarMenu() {
    const router = useRouter()
    const [anchorEl, setAnchorEl] = React.useState(null);
    const open = Boolean(anchorEl);
    const handleClick = (event) => {
        setAnchorEl(event.currentTarget);
    };
    const handleClose = () => {
        setAnchorEl(null);
    };
    const handleLogout = () => {
        localStorage.clear()
        router.push('/auth/login')
    }
    return (
        <>
            <IconButton
                id="basic-button"
                size="large"
                aria-controls="basic-menu"
                aria-haspopup="true"
                aria-expanded={open ? 'true' : undefined}
                onClick={handleClick}
            >
                <AccountCircle sx={{ color: 'white' }} />
            </IconButton>
            <Menu
                id="basic-menu"
                anchorEl={anchorEl}
                open={open}
                onClose={handleClose}
                MenuListProps={{
                    'aria-labelledby': 'basic-button',
                }}
            >
                <MenuItem onClick={handleClose}>Profile</MenuItem>
                <MenuItem onClick={handleClose}>My account</MenuItem>
                <MenuItem onClick={handleLogout}>Logout</MenuItem>
            </Menu>
        </>
    );
}

Solution 8 - Reactjs

All that stuff didn't work for me. So i gave the button an id and put it on the menu using javascript:

<IconButton id="btnPerfil" onClick={this.toggleMenuPerfilOpen}>
    <AccountCircle color="inherit" />
</IconButton>
<Menu
  anchorPosition={{
    vertical: 'top',
    horizontal: 'center'
  }}
  anchorEl={document.getElementById('btnPerfil')}
  keepMounted
  open={this.state.isMenuPerfilOpen}
  onClose={this.toggleMenuPerfilOpen}
>...</Menu>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSti&#241;oView Question on Stackoverflow
Solution 1 - ReactjsEmmyView Answer on Stackoverflow
Solution 2 - ReactjsDavit MkrtchyanView Answer on Stackoverflow
Solution 3 - ReactjsAngel IgaretaView Answer on Stackoverflow
Solution 4 - ReactjsAfsar AliView Answer on Stackoverflow
Solution 5 - ReactjsMatheusView Answer on Stackoverflow
Solution 6 - ReactjsMatias LatorracaView Answer on Stackoverflow
Solution 7 - ReactjsShahnadView Answer on Stackoverflow
Solution 8 - ReactjsAnderson BressaneView Answer on Stackoverflow