Show Dialog on MenuItem click - reactjs

Is there a way to have a Dialog component pop up when you click on a MenuItem in a Material-UI Menu? I have a header component that returns the below JSX:
return (
<AppBar
iconElementLeft={<a href='/'><Avatar src="/static/images/favicon.ico" style={{ marginTop:4 }} /></a>}
title= {
<div>
{"Application"}
{displaySearch?<div style={{display:'inline-block', marginLeft:20, width:500}}><Search location={location}/></div>:null}
<div style={{float:'right'}}>
{logoUri ? <img src={logoUri} style={{ height:40, verticalAlign:'middle',borderRadius:3,overflow:'hidden'}} /> : null}
</div>
</div>
}
iconElementRight={
<IconMenu
iconButtonElement={
<IconButton><MoreVertIcon /></IconButton>
}
targetOrigin={{ horizontal: 'right', vertical: 'top' }}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
>
{
menuItems.map(
menuItem => <MenuItem containerElement={<Link to={menuItem.uri} />} primaryText={menuItem.primaryText} key={menuItem.key} />)
}
<MenuItem href='#' primaryText={'about'} onTouchTap={()=>{}} />
<MenuItem href='/auth/logout' primaryText={'logout'} />
</IconMenu>
}
<Dialog ref="dialog" title="version 1.0" open={true}>
Version: {version}
</Dialog>
/>
)
I'm just trying to wire up the 'about' menu item to the dialog that pops up and displays the version information that I pass along to the page, but once I include the Dialog in the IconMenu, if you click on the IconMenu, nothing shows and I get an error:
"Menu.js:222 Uncaught TypeError: Cannot set property 'opacity' of undefined".
If I remove the Dialog component, my MenuItem works as intended. I'm not sure how exactly I can wire up a MenuItem to a Dialog. Is it possible to have a MenuItem trigger a Dialog component in Material-UI?

You could create the dialog as a menu item:
import MenuDialog from './MenuDialog';
Then
<IconMenu
...
<MenuDialog />
...
</IconMenu>
And now in a seperate MenuDialog.js file, as a component which is imported above
render(){
const actions = [<FlatButton
label="Close"
primary={true}
onClick={this.handleClose} />
]
return(
<div>
<MenuItem onClick={this.handleOpen}>Press for dialog </MenuItem>
<Dialog
title={Dialog name}
actions={actions}
modal={false}
open={this.state.open}
onRequestClose={this.handleClose}> Dialog writing
</Dialog>
</div>
)
}

Related

MUI two tooltips on one component

I want to display two tooltips on a button. However, I can't find any way to do it without errors in the console.
My goal:
Minimal reproducible example
import * as React from 'react';
import { Tooltip, Button, Box } from '#mui/material';
export default function BasicTooltip() {
return (
<Box sx={{ margin: 10 }}>
<Tooltip title="Tooltip on top" placement="top">
<Tooltip title="Tooltip on button" placement="bottom">
<Button>Hello</Button>
</Tooltip>
</Tooltip>
</Box>
);
}
Error I'm getting in the console with this code:
MUI: You have provided a title prop to the child of Tooltip.
Remove this title prop Tooltip on button or the Tooltip component.
Link to stackblitz: https://stackblitz.com/edit/react-qgtibd?file=demo.js
I already tried to isolate the inner tooltip with button in another component like this, but it did not work:
import * as React from 'react';
import { Tooltip, Button, Box } from '#mui/material';
const MyButton = React.forwardRef(({ tooltipText }, ref) => (
<Tooltip title={tooltipText} placement="bottom">
<Button ref={ref}>Hello</Button>
</Tooltip>
));
export default function BasicTooltip() {
return (
<Box sx={{ margin: 10 }}>
<Tooltip title="Tooltip on top" placement="top">
<MyButton tooltipText="Tooltip on bottom" />
</Tooltip>
</Box>
);
}
edit: I also can't put a div nor React.fragment between those tooltips, because it completely screws up the layout in my real case scenario.
Looks like you need to isolate the tooltips from one another
<Box sx={{ margin: 10 }}>
<Tooltip title="Tooltip on top" placement="top">
<Box>
<Tooltip title="Tooltip on button" placement="bottom">
<Button>Hello</Button>
</Tooltip>
</Box>
</Tooltip>
</Box>
modified stackblitz with the aligment

Custom Menu Item in MUI Data Grid Toolbar

I'm currently using the Data Grid Toolbar (a feature of the Material-UI Data Grid component) because I want the Column Show/Hide component, but I also want to add my own menu item in the form of an IconButton with a Menu that opens when clicked. The issue is when you click said button, the Toolbar appears to re-render, which causes the Menu to lose its anchor and render in the upper left. Is there a special way to get an anchor within the Data Grid Toolbar for the Menu popper to appear in the correct location?
function CustomToolbar() {
return (
<GridToolbarContainer>
<Box
height="65px"
width="100%"
display="flex"
flexDirection="row"
justifyContent="center"
>
<Box width="300px" display="flex" justifyContent="flex-start" alignItems="center">
<GridToolbarColumnsButton sx={{ ml: 2 }} />
</Box>
<Box width="100%" alignSelf="center" textAlign="center">
<Typography sx={{ flex: "1 1 100%" }} variant="h6" component="div">
Title Goes Here
</Typography>
</Box>
<Box width="300px" display="flex" justifyContent="flex-end" alignItems="center">
<Tooltip title="Filter">
<IconButton
color="primary"
component="span"
disabled={loading}
sx={{ mr: 2 }}
onClick={handleMenuClick}
>
<FilterList />
</IconButton>
</Tooltip>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={() => handleClose(menuState, filters)}
transformOrigin={{ horizontal: "right", vertical: "top" }}
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
PaperProps={MenuProps}
>
<MenuItem /> //Clipped
<MenuItem /> //Clipped
<MenuItem /> //Clipped
</Menu>
</Box>
</Box>
</GridToolbarContainer>
);
}
You must create the Toolbar component outside of your component that declares the DataGrid, and get the properties you need through the DataGrid's componentsProps property.
GridToolbarCustom Component:
type Props = {
selectionModel: GridSelectionModel;
}
const GridToolbarCustom = ({ selectionModel }: Props) => {
const [anchorElMenu, setAnchorElMenu] = useState<null | HTMLButtonElement>(null);
const openMenu = Boolean(anchorElMenu);
return (
<GridToolbarContainer>
<Grid container item xs>
{/* default buttons */}
<GridToolbarColumnsButton />
<GridToolbarFilterButton />
<GridToolbarDensitySelector />
<GridToolbarExport />
</Grid>
<Grid>
<Button
variant="contained"
size="small"
disabled={selectionModel.length === 0}
startIcon={<MoreVertIcon />}
onClick={(event: MouseEvent<HTMLButtonElement>) => {
setAnchorElMenu(event.currentTarget);
}}
>
Actions
</Button>
<Menu
id="menu-options"
anchorEl={anchorElMenu}
open={openMenu}
onClose={() => {
setAnchorElMenu(null);
}}
>
<MenuItem /> //Clipped
<MenuItem /> //Clipped
<MenuItem /> //Clipped
</Menu>
</Grid>
</GridToolbarContainer>
);
}
export default GridToolbarCustom;
MyComponent:
import GridToolbarCustom from './GridToolbarCustom';
const MyComponent = () => {
const [selectionModel, setSelectionModel] = useState<GridSelectionModel>([]);
return (
<DataGrid
//Clipped
components={{
Toolbar: GridToolbarCustom,
}}
componentsProps={{
toolbar: {
selectionModel,
},
}}
checkboxSelection
onSelectionModelChange={(newSelectionModel) => {
setSelectionModel(newSelectionModel);
}}
selectionModel={selectionModel}
/>
);
};

Material UI - Menu Component locks body scrollbar

I have made a dropdown menu using Material-ui Menu component.
The problem is once that dropdown menu is open, the body scrollbar disappears and can not scroll over the page.
I tried to find answers but there are only a few answers for Popper, Popover or Select component but seems like no answer for Menu component.
DropDownMenu component is like this.
import React from 'react'
import Menu from '#material-ui/core/Menu'
import MuiMenuItem from '#material-ui/core/MenuItem'
import styled from 'styled-components'
import MoreVertIcon from '#material-ui/icons/MoreVert'
import IconButton from '#material-ui/core/IconButton'
import SendIcon from '#material-ui/icons/Send'
import ListItemIcon from '#material-ui/core/ListItemIcon'
import ListItemText from '#material-ui/core/ListItemText'
const MenuItem = styled(MuiMenuItem)`
justify-content: flex-end;
`
export default function DropDownMenu() {
const [anchorEl, setAnchorEl] = React.useState(null)
const handleClick = (event) => {
setAnchorEl(event.currentTarget)
}
const handleClose = () => {
setAnchorEl(null)
}
return (
<div>
<IconButton
style={{ padding: 0 }}
aria-label="more"
aria-controls="long-menu"
aria-haspopup="true"
onClick={handleClick}
>
<MoreVertIcon style={{ fontSize: 15 }} />
</IconButton>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
getContentAnchorEl={null}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
>
<MenuItem onClick={handleClose}>
<ListItemIcon>
<SendIcon fontSize="small" />
</ListItemIcon>
<ListItemText primary="Sent mail" />
</MenuItem>
<MenuItem onClick={handleClose}>
<ListItemIcon>
<SendIcon fontSize="small" />
</ListItemIcon>
<ListItemText primary="Sent mail" />
</MenuItem>
<MenuItem onClick={handleClose}>
<ListItemIcon>
<SendIcon fontSize="small" />
</ListItemIcon>
<ListItemText primary="Sent mail" />
</MenuItem>
</Menu>
</div>
)
}
Sharpening code to Menu props is as following.
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
getContentAnchorEl={null}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
>
<MenuItem onClick={handleClose}>
<ListItemIcon>
<SendIcon fontSize="small" />
</ListItemIcon>
<ListItemText primary="Sent mail" />
</MenuItem>
The working example can be seen https://codesandbox.io/s/billowing-cache-042j1?file=/src/App.js
Thanks in advance.
Set the disableScrollLock prop to true. This prop is from the Material UI Modal component but it is also made available for the Menu component.
<Menu
...others
disableScrollLock={true}
>
</Menu>
You should use Popper instead of Menu. You should also create ref and use it for IconButton or Button.
import React from 'react'
import ClickAwayListener from '#material-ui/core/ClickAwayListener'
import Grow from '#material-ui/core/Grow'
import Paper from '#material-ui/core/Paper'
import Popper from '#material-ui/core/Popper'
import MenuItem from '#material-ui/core/MenuItem'
import MenuList from '#material-ui/core/MenuList'
import IconButton from '#material-ui/core/IconButton'
import MoreVertIcon from '#material-ui/icons/MoreVert'
import SendIcon from '#material-ui/icons/Send'
import ListItemIcon from '#material-ui/core/ListItemIcon'
import ListItemText from '#material-ui/core/ListItemText'
export default function DropDownMenu(props) {
const [open, setOpen] = React.useState(false)
const anchorRef = React.useRef(null)
const handleToggle = () => {
setOpen((prevOpen) => !prevOpen)
}
const handleClose = (event) => {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return
}
setOpen(false)
}
function handleListKeyDown(event) {
if (event.key === 'Tab') {
event.preventDefault()
setOpen(false)
}
}
const handleClick = () => {
// handle menu click here
setOpen(false)
}
return (
<div>
<IconButton
ref={anchorRef}
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
size="small"
>
<MoreVertIcon fontSize="small" />
</IconButton>
<Popper open={open} anchorEl={anchorRef.current} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="menu-list-grow" onKeyDown={handleListKeyDown}>
<MenuItem onClick={handleClick}>
<ListItemIcon>
<SendIcon fontSize="small"/>
</ListItemIcon>
<ListItemText primary="Sent mail" />
</MenuItem>
<MenuItem onClick={handleClick}>
<ListItemIcon>
<SendIcon fontSize="small"/>
</ListItemIcon>
<ListItemText primary="Sent mail" />
</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
)
}
There is also an example code of it at Material UI Menus Documentation.

react material ui grow on left side

How to make the context menu open not in the center of the button, but to the left of the button? With using properties Material UI.
Working example from link:
https://codesandbox.io/s/2f33z
Now this:
I want this:
Here is a link to an example from the documentation:
https://material-ui.com/components/menus/#menulist-composition
<div>
<Button
ref={anchorRef}
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
>
Toggle Menu Grow
</Button>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="menu-list-grow" onKeyDown={handleListKeyDown}>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
Your Popper component should have a placement property of value bottom-start:
// ...
<Popper
placement="bottom-start"
// ...
>
// ...
For more options look here: https://material-ui.com/components/popper/#positioned-popper.

Unable to show icon after showing menu Items in reactjs

I have created a dropdown for the icon where when the icon is clicked, it will show the dropdown. Once we hover on Card then the three dots icon will appear. But my objective is even after showing dropdown the icon should appear. but here is my code, it is disappearing. Can anyone help me with this query?
Here is the code:
<Card>
<CardHeader
className={classes.header}
avatar={<Avatar aria-label="recipe">R</Avatar>}
action={
<div>
<IconButton
id="simple-menu"
className={classes.showIcon}
aria-label="settings"
aria-controls="simple-menu"
onClick={this.handleClick}
>
<MoreVertIcon />
</IconButton>
<Menu
style={{ marginTop: "35px" }}
id="simple-menu"
keepMounted
anchorEl={this.state.menu}
open={Boolean(this.state.menu)}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose}>Profile</MenuItem>
<MenuItem onClick={this.handleClose}>change password</MenuItem>
<MenuItem onClick={this.handleClose}>Logout</MenuItem>
</Menu>
</div>
}
title="Shrimp and Chorizo Paella"
subheader="September 14, 2016"
/>
</Card>
Here is the sample code
Create a style className which sets the icon visibility to visible. Conditionally assign the class to the parent div only when the menu is open i.e. check for this.state.menu && classes.menu.
Style
const styles = theme => ({
header: {
background: "grey",
"&:hover": {
background: "yellow",
"& $showIcon": {
visibility: "visible"
}
}
},
showIcon: {
visibility: "hidden"
},
menu: {
"& $showIcon": {
visibility: "visible"
}
}
});
JSX
<Card>
<CardHeader
className={classes.header}
avatar={<Avatar aria-label="recipe">R</Avatar>}
action={
<div className={this.state.menu && classes.menu}>
<IconButton
id="simple-menu"
className={classes.showIcon}
aria-label="settings"
aria-controls="simple-menu"
onClick={this.handleClick}
>
<MoreVertIcon />
</IconButton>
...
Working copy of your code is here

Resources