Not able to copy to clipboard from Popper which is inside Dialogue in material-UI - javascript

Steps to reproduce the bug here: (Try to open in Firefox, I was almost crashed the chrome :P) https://codesandbox.io/s/73z5293391
Click on the OPEN SIMPLE DIALOGUE button. Now you see a dialogue, Click on the TOGGLE POPPER button.
Now you see a Popper which has an input box and a COPY button.
You need to copy on the text inside the input box in this case hello.
So I am not able to copy to clipboard actually.
First I thought it might be a problem with Dialogue. But no. In just a Dialogue it works. But not on Popper which pops up from the Dialogue(Only for Popper also it works).
Can you help me to copy to clipboard in this situation?
Once again the source code:
import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import Button from "#material-ui/core/Button";
import Avatar from "#material-ui/core/Avatar";
import List from "#material-ui/core/List";
import ListItem from "#material-ui/core/ListItem";
import ListItemAvatar from "#material-ui/core/ListItemAvatar";
import ListItemText from "#material-ui/core/ListItemText";
import DialogTitle from "#material-ui/core/DialogTitle";
import Dialog from "#material-ui/core/Dialog";
import PersonIcon from "#material-ui/icons/Person";
import AddIcon from "#material-ui/icons/Add";
import Typography from "#material-ui/core/Typography";
import blue from "#material-ui/core/colors/blue";
import DialogContent from "#material-ui/core/DialogContent";
import Popper from "#material-ui/core/Popper";
const emails = ["username#gmail.com", "user02#gmail.com"];
const styles = {
avatar: {
backgroundColor: blue[100],
color: blue[600]
}
};
class SimpleDialog extends React.Component {
state = {
anchorEl: null,
openPopper: false
};
handleClose = () => {
this.props.onClose(this.props.selectedValue);
};
handleListItemClick = value => {
this.props.onClose(value);
};
copytoClipBoard = () => {
this.hello.select();
try {
return document.execCommand("copy");
} catch (err) {
console.log("Oops, unable to copy");
}
};
handleClick = event => {
const { currentTarget } = event;
this.setState(state => ({
anchorEl: currentTarget,
openPopper: !state.openPopper
}));
};
render() {
const { classes, onClose, selectedValue, ...other } = this.props;
const { anchorEl, openPopper } = this.state;
const id = openPopper ? "simple-popper" : null;
return (
<Dialog
onClose={this.handleClose}
aria-labelledby="simple-dialog-title"
{...other}
>
<DialogTitle id="simple-dialog-title">Set backup account</DialogTitle>
<DialogContent>
<Button
aria-describedby={id}
variant="contained"
onClick={this.handleClick}
>
Toggle Popper
</Button>
<Popper
id={id}
open={openPopper}
anchorEl={anchorEl}
style={{ zIndex: 10000 }}
>
<input
value="hello"
readOnly
type="text"
ref={node => (this.hello = node)}
/>
<Button onClick={this.copytoClipBoard}> Copy </Button>
</Popper>
<List>
{emails.map(email => (
<ListItem
button
onClick={() => this.handleListItemClick(email)}
key={email}
>
<ListItemAvatar>
<Avatar className={classes.avatar}>
<PersonIcon />
</Avatar>
</ListItemAvatar>
<ListItemText primary={email} />
</ListItem>
))}
<ListItem
button
onClick={() => this.handleListItemClick("addAccount")}
>
<ListItemAvatar>
<Avatar>
<AddIcon />
</Avatar>
</ListItemAvatar>
<ListItemText primary="add account" />
</ListItem>
</List>
</DialogContent>
</Dialog>
);
}
}
SimpleDialog.propTypes = {
classes: PropTypes.object.isRequired,
onClose: PropTypes.func,
selectedValue: PropTypes.string
};
const SimpleDialogWrapped = withStyles(styles)(SimpleDialog);
class SimpleDialogDemo extends React.Component {
state = {
open: false,
selectedValue: emails[1]
};
handleClickOpen = () => {
this.setState({
open: true
});
};
handleClose = value => {
this.setState({ selectedValue: value, open: false });
};
render() {
return (
<div>
<Typography variant="subtitle1">
Selected: {this.state.selectedValue}
</Typography>
<br />
<Button
variant="outlined"
color="primary"
onClick={this.handleClickOpen}
>
Open simple dialog
</Button>
<SimpleDialogWrapped
selectedValue={this.state.selectedValue}
open={this.state.open}
onClose={this.handleClose}
/>
</div>
);
}
}
export default SimpleDialogDemo;

#akhila-hegde You can add disablePortal to the Popper to solve this.
Note that problem is not with Copy to clipboard. Problem is that you are not able to select the text in the field (because it is in a Portal).
Here is Sandbox link with disablePortal set to true - https://codesandbox.io/s/lxjwj3p8m9

Related

How do I get the className of a event.target in React?

I am trying to get the user.id of the user that I clicked on, so that I can use it as a query parameter in a fetch(). However, what setClickedUserId is passing/assigning to my clickedUserId state is the following: MuiButtonBase-root%20MuiListItem-root%201%20MuiListItem-gutters%20MuiListItem-button
----My code:
import React from 'react';
import {makeStyles} from '#material-ui/core/styles';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemIcon from '#material-ui/core/ListItemIcon';
import ListItemText from '#material-ui/core/ListItemText';
import Collapse from '#material-ui/core/Collapse';
import ExpandLess from '#material-ui/icons/ExpandLess';
import ExpandMore from '#material-ui/icons/ExpandMore';
import PersonIcon from '#material-ui/icons/Person';
import AddBoxOutlinedIcon from '#material-ui/icons/AddBoxOutlined';
// Global context
import globalContext from './globalContext';
const useStyles = makeStyles((theme) => ({
root: {
marginTop: theme.spacing(-2.0),
width: '100%',
maxWidth: 360,
backgroundColor: '#3F0E40',
color: 'white',
},
nested: {
marginLeft: theme.spacing(-3.5),
},
nestedAdd: {
marginLeft: theme.spacing(3.5),
},
nestedAddText: {
marginLeft: theme.spacing(0.5),
},
}));
/**
*#return{any} nestedList
*/
export default function DmsList() {
const classes = useStyles();
const [open, setOpen] = React.useState(true);
console.log('I am inside DmsList!!');
// Global Context
const {setMobileOpen} = React.useContext(globalContext);
const {currentDmdWith} = React.useContext(globalContext);
const {setChannel} = React.useContext(globalContext);
const {clickedDms, setClickedDms} = React.useContext(globalContext);
const {setClickedUserId} = React.useContext(globalContext);
const handleClickUser = (event) => {
setMobileOpen(false);
setClickedDms('true');
setChannel(event.target.innerText);
setClickedUserId(event.target.className);
console.log(clickedDms);
};
const handleClickAdd = () => {
setMobileOpen(false);
};
const handleClick = () => {
setOpen(!open);
};
return (
<List
component="nav"
aria-labelledby="nested-list-subheader"
className={classes.root}
>
<ListItem button
onClick={handleClick}>
{open ? <ExpandLess /> : <ExpandMore />}
<ListItemText primary="Direct Messages" />
</ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>
<List component="div" disablePadding className={classes.nested}>
{currentDmdWith.map((user) => (
<ListItem button className={user.id} onClick={handleClickUser}>
<ListItemIcon className={user.id}>
</ListItemIcon>
<PersonIcon className={user.id} color='white'/>
<ListItemText className={user.id} primary={user.name} />
</ListItem>
))}
<ListItem button
onClick={handleClickAdd}
className={classes.nested}>
<ListItemIcon>
</ListItemIcon>
<AddBoxOutlinedIcon className={classes.nestedAdd}/>
<ListItemText
className={classes.nestedAddText} primary="Add Teammate" />
</ListItem>
</List>
</Collapse>
</List>
);
}
I would use event.target.id, because it actually gets the div's id and not a bunch of mumbo jumbo, but when I do put id = {user.id} in a ListItem I have to click on a very specific spot, the leftmost side, because if I click on an a person icon or the area with text, event.target.id is a assigned a blank and makes my fetch() return a 404 error.
Instead of trying to read the information out of the Event object, pass the info that you need in the handleClickUser function through the onClick prop.
<ListItem
button
className={user.id}
onClick={() => handleClickUser(user.id)}
>
const handleClickUser = (userId) => {
setClickedUserId(userId);
};

unable to update the state through custom react hook

I am trying to create a custom hook which returns a custom drawer and a button(to toggle the state of drawer). I am managing the state in custom hook itself.
This is my custom hook for returning the drawer and a button
import React from "react";
import clsx from "clsx";
import { makeStyles } from "#material-ui/core/styles";
import Drawer from "#material-ui/core/Drawer";
import List from "#material-ui/core/List";
import Divider from "#material-ui/core/Divider";
import ListItem from "#material-ui/core/ListItem";
import ListItemIcon from "#material-ui/core/ListItemIcon";
import ListItemText from "#material-ui/core/ListItemText";
import InboxIcon from "#material-ui/icons/MoveToInbox";
import MailIcon from "#material-ui/icons/Mail";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faBars } from "#fortawesome/free-solid-svg-icons";
import { Button } from "#material-ui/core";
const useStyles = makeStyles({
list: {
width: 250
},
fullList: {
width: "auto"
}
});
export default function useTemporaryDrawer(toggle) {
const classes = useStyles();
const [state, setState] = React.useState({
right: false
});
const toggleDrawer = (anchor, open) => (event) => {
if (
event.type === "keydown" &&
(event.key === "Tab" || event.key === "Shift")
) {
return;
}
alert("setting");
setState({ ...state, [anchor]: open });
};
const onButtonClick = (e) => {
toggleDrawer("right", true)(e);
};
const Toggler = (
<Button
style={{
marginTop: "10px"
}}
onClick={onButtonClick}
startIcon={<FontAwesomeIcon icon={faBars} style={{ color: "#fff" }} />}
></Button>
);
const list = (anchor) => (
<div
className={clsx(classes.list, {
[classes.fullList]: anchor === "top" || anchor === "bottom"
})}
role="presentation"
onClick={toggleDrawer(anchor, false)}
onKeyDown={toggleDrawer(anchor, false)}
>
<List>
{["Inbox", "Starred", "Send email", "Drafts"].map((text, index) => (
<ListItem button key={text}>
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
<Divider />
<List>
{["All mail", "Trash", "Spam"].map((text, index) => (
<ListItem button key={text}>
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
</div>
);
const CustomDrawer = (
<Drawer
anchor={"right"}
open={state["right"]}
onClose={toggleDrawer("right", false)}
>
{list("right")}
</Drawer>
);
return {
CustomDrawer,
setState,
state,
Toggler
};
}
Then, I am trying to update the state through Toggle button which I am using in Header. This is my header
import React from "react";
import styles from "./Header.module.css";
import useTemporaryDrawer from "../Drawer/useTemporaryDrawer";
const Header = (props) => {
const { Toggler } = useTemporaryDrawer();
return <div className={styles.headerForApp}>{Toggler}</div>;
};
export default Header;
When I press the toggle button, it does update the state but it does not update the open property of drawer. In short I am not able to open the drawer through toggle button. Please help.
Here is the sandbox
https://codesandbox.io/s/customhooksnotupdatingstate-d7mfz?file=/src/components/Drawer/useTemporaryDrawer.js
If I have 2 components: A and B, and each of them have setState hook to update variable state, you won't expect setState('a') inside A to make any difference to state in B, will you? But then you create 2 components, each of them with their independent state and expect those states to be shared somehow. Toggle in Header changes state of Header, and Drawer in Dashboard had no visibility of these changes. As an option you can pass Toggler to the Header as a prop
<Header Toggler={Toggler} />
const Header = (props) => {
return <div className={styles.headerForApp}>{props.Toggler}</div>;
};

findDOMNode is deprecated in StrictMode React material UI

I am getting this error on my React material UI project
By looking at the error I guess it comes somewhere inside the Drawer.js component.
This is my full Drawer.js component
import React, { Fragment, useState } from "react";
import clsx from "clsx";
import { makeStyles, useTheme } from "#material-ui/core/styles";
import Drawer from "#material-ui/core/Drawer";
import { List, Collapse } from "#material-ui/core";
import Divider from "#material-ui/core/Divider";
import ListItem from "#material-ui/core/ListItem";
import IconButton from "#material-ui/core/IconButton";
import ListItemText from "#material-ui/core/ListItemText";
import { toggleDrawer } from "../../store/actions/authActions";
import ExpandLess from "#material-ui/icons/ExpandLess";
import ExpandMore from "#material-ui/icons/ExpandMore";
import ChevronLeftIcon from "#material-ui/icons/ChevronLeft";
import ChevronRightIcon from "#material-ui/icons/ChevronRight";
// import ClickAwayListener from '#material-ui/core/ClickAwayListener'
import { useHistory } from 'react-router-dom';
import { connect } from "react-redux";
import { withRouter } from "react-router";
const useStyles = makeStyles({
list: {
width: 250,
},
fullList: {
width: "auto",
},
});
function TemporaryDrawer(props) {
const classes = useStyles();
const theme = useTheme();
// const [open, setOpen] = React.useState(false);
const [openIndex, setOpenIndex] = useState(0);
let history = useHistory();
// const handleDrawerOpen = () => {
// setOpen(true);
// };
const handleDrawerClose = () => {
props.toggleDrawer();
};
const handleClick = (index) => {
if (openIndex === index) {
setOpenIndex(-1);
} else {
setOpenIndex(index);
}
};
const onToggle = () => (event) => {
if (
event.type === "keydown" &&
(event.key === "Tab" || event.key === "Shift")
) {
return;
}
props.toggleDrawer();
};
const onRoute = (path) => {
// props.history.push(path);
history.push(path);
props.toggleDrawer();
};
const list = (anchor) => (
<div
className={clsx(classes.list, {
[classes.fullList]: anchor === "top" || anchor === "bottom",
})}
role="presentation"
>
<div className={classes.drawerHeader}>
<IconButton onClick={handleDrawerClose}>
{theme.direction === "ltr" ? (
<ChevronLeftIcon />
) : (
<ChevronRightIcon />
)}
</IconButton>
</div>
<Divider />
<List>
{props.permissions.map((route, index) => (
<Fragment key={index}>
<ListItem button onClick={(e) => handleClick(index)}>
<ListItemText primary={route.name} />
{index === openIndex ? <ExpandLess /> : <ExpandMore />}
</ListItem>
{route.children.length && (
<Collapse
in={openIndex === index ? true : false}
timeout="auto"
unmountOnExit
>
<List component="div" disablePadding>
{route.children.map((child, idx) => (
<ListItem
button
className={classes.nested}
key={idx}
onClick={() => onRoute(child.path)}
>
<ListItemText primary={child.name} />
</ListItem>
))}
</List>
<Divider />
</Collapse>
)}
</Fragment>
))}
</List>
{/* <Divider /> */}
</div>
);
return (
<div>
{props.token && (
<Drawer
anchor="left"
open={props.isDrawerOpen}
onClose={onToggle("left", false)}
variant="persistent"
>
{list("left")}
</Drawer>
)}
</div>
);
}
const mapStateToProps = (state) => {
return {
isDrawerOpen: state.auth.isDrawerOpen,
token: state.auth.token,
permissions: state.auth.routes,
};
};
export default withRouter(
connect(mapStateToProps, { toggleDrawer })(TemporaryDrawer)
);
I go through this error and some say this is a problem in MUI library and no way to fix this. But I believe there must be a workaround for this. This causes serious problems for UI.
Where this error comes from and what can I do to fix this?
Any help!
Thanks in advance. =)
I use material UI 4.11.0
and react 16
You only need to create a new childComponent with react.forwardRef passing respective props and refs:
const ChildComponent = React.forwardRef((props, ref) =>
<div ref={ref}>
<yourChildcomponent {...props} />
</div>
);
In your render change the name of the original Child for the new:
<ChildComponent... />

Deleting a child component in react

So first, this web-app is one of my first web-apps using react, and I have done it using JavaScript and C# .net core.
What I want to do is, on click of a Button i want to creat a component, that appears on screen.
And so far that part is working well.
import FusePageSimple from '#fuse/core/FusePageSimple';
import { makeStyles } from '#material-ui/core/styles';
import Typography from '#material-ui/core/Typography';
import React, {ParentComponent, useEffect, useRef,useState } from 'react';
import { useDispatch } from 'react-redux';
import LeftSideBar from './components/SideBarComp';
import RightSideComp from './components/RightSideComp';
import Hidden from '#material-ui/core/Hidden';
import Icon from '#material-ui/core/Icon';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import { tokensToRegExp } from 'path-to-regexp';
const useStyles = makeStyles(theme => ({
layoutRoot: {}
}));
function Dashboard(props) {
const [compCount, setCompCount] = useState(0);
const [component, setComponent] = useState('');
const eventhandler = data => {
if(data.eliminar === 1){
setComponent(component.filter((item) => item.props.RowNum !== data.RowNum));
}
};
const classes = useStyles(props);
const pageLayout = useRef(null);
const onAddChild = () => {
setCompCount(compCount + 1);
}
useEffect(() => {
const compArry = [...component];
if(compCount > 0 ){
compArry.push(<RightSideComp key={compCount} RowNum={compCount} onChange={eventhandler}/>)
}
setComponent(compArry);
}, [compCount]);
return (
<FusePageSimple
classes={{
root: classes.layoutRoot
}}
header={
<div className="flex flex-col flex-1">
<div className="flex items-center p-24 px-12">
<Hidden lgUp>
<IconButton
onClick={ev => pageLayout.current.toggleLeftSidebar()}
aria-label="open left sidebar"
>
<Icon>menu</Icon>
</IconButton>
</Hidden>
<div className="flex-1 lg:px-12">
<h4>Header</h4>
</div>
</div>
</div>
}
contentToolbar={
<div className="px-24">
<h4>Content Toolbar</h4>
</div>
}
content={
<div className="p-24">
<h4>Content</h4>
<br />
{component}
</div>
}
leftSidebarHeader={
<div className="p-24">
<h4>Sidebar Header</h4>
</div>
}
leftSidebarContent={
<div className="p-24">
<Button variant="contained" color="primary"
onClick={ev => onAddChild()}>
Novo
</Button>
{/* <Button variant="contained" color="primary">Copiar</Button> */}
<br />
<LeftSideBar />
</div>
}
innerScroll
ref={pageLayout}
/>
);
}
export default Dashboard;
Thats the code of the parent.
So by clicking the button "Novo"(Means "New" in english) I call the onAddChild(), I add To the compCount and after with the UseEffect I add the child component. I pass 2 props to that Child RowNum, the number of components that I am creating, and an event that is trigger on state change.
import React,{ useEffect, useState } from 'react';
import { createSlice, createAsyncThunk } from '#reduxjs/toolkit';
import TextField from '#material-ui/core/TextField';
import { makeStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import Divider from '#material-ui/core/Divider';
const useStyles = makeStyles(theme => ({
root: {
'& .MuiTextField-root': {
margin: theme.spacing(2),
width: '25ch'
}
}
}));
function RightSideComp(props) {
const classes = useStyles();
const [component, setComponent] = useState({
dataInicio: (!(props.datastate) ? '' : props.datastate.dataInicio),
dataFim: (!(props.datastate) ? '' : props.datastate.dataFim),
descricao: (!(props.datastate) ? '' : props.datastate.descricao),
RowNum: props.RowNum,
eliminar: 0,
copiar: 0
});
console.log(component);
const handleChangeInput = event => {
const { name, value } = event.target;
setComponent(prevState => ({
...prevState,
[name]: value
}));
};
const handleChangeButtonCopiar = event => {
setComponent(preState => ({ ...preState, copiar: 1 }));
};
const handleChangeButtonEliminar = event => {
setComponent(preState => ({ ...preState, eliminar: 1 }));
};
useEffect(() => {
props.onChange(component);
}, [component]);
return (
<div>
<div className={classes.root}>
<TextField
id="dataInicio"
label="Data Inicio"
name="dataInicio"
type="datetime-local"
className={classes.textField}
value={component.dataInicio}
onChange={ev => handleChangeInput(ev)}
InputLabelProps={{
shrink: true
}}
/>
<TextField
id="dataFim"
name="dataFim"
label="Data do Fim"
type="datetime-local"
className={classes.textField}
value={component.dataFim}
onChange={ev => handleChangeInput(ev)}
InputLabelProps={{
shrink: true
}}
/>
<TextField
id="outlined-multiline-flexible"
label="Multiline"
name="descricao"
multiline
rowsMax={5}
value={component.descricao}
onChange={ev => handleChangeInput(ev)}
variant="outlined"
/>
<div>
<Button variant="contained" color="primary" onClick={ev => handleChangeButtonCopiar(ev)}>
Copiar
</Button>
<Button variant="contained" color="secondary" onClick={ev => handleChangeButtonEliminar(ev)}>
Eliminar
</Button>
</div>
</div>
<Divider />
</div>
);
}
export default React.memo(RightSideComp);
and thats my child component.
So my error is when I change the eliminar("delete" in english) that component gets deleted. And with the code I have, if it is the last row it deletes fine but, if it is one from the middle it delets that one and all the others that are below the one I clicked. I tried with slice and didnt work well too. I am missing something, but what?
thanks for your time
I think you need to use 'useRef'
const refsList = React.useRef([]);
then when you create something
compArry.push(<RightSideComp ref={refsList[compCount]} key={compCount} RowNum={compCount} onChange={eventhandler}/>)
now you can directly do anything you want with any elements based on this ref, eg. refsList[0].current will be the actual 1st element
refsList[0].current.remove()

How to set a HTML element ID on a material-ui component?

I have a website built with Gatsby.js using the Material-UI.
Specific problem is this: I want to use the Google Tag Manager "Element Visibility" triggers. If some HTML element becomes visible, GTM should fire some GA tag.
Question is this: how can I specify the HTML ID for a material-ui component for GTM (or anything else) to find it?
First example:
// ...react imports omitted...
import makeStyles from '#material-ui/core/styles/makeStyles';
import Box from '#material-ui/core/Box';
import Grid from '#material-ui/core/Grid';
import CloseIcon from '#material-ui/icons/Close';
import Link from '~components/Link';
import ButtonSubmit from '~components/form-buttons/ButtonSubmit';
import Container from '~components/Container';
// ... all other imports are in-house code
const useStyles = makeStyles(theme => ({ /* ...styles... */}));
const GuestUserSoftSaleSecondPopup = ({ which, ...rest }) => {
const classes = useStyles();
// ...setup code omitted...
return (
<Box bgcolor="#474d5c" width="100%" py={4} className={classes.banner}>
<Container>
<Grid container direction="row" justify="space-between" alignItems="center" spacing={2}>
<Grid item xs={12} sm={1} md={3} lg={4}>
<CloseIcon onClick={handleClose} size="large" className={classes.closeIcon} />
</Grid>
<Grid item xs={12} sm={7} md={5} lg={4}>
<Link to="/subscribe" variant="h5" className={classes.linkStyle}>
Become a member for full access
</Link>
</Grid>
<Grid item xs={12} sm={4} className={classes.buttonPosition}>
<Link to="/subscribe" underline="none" className={classes.linkStyle}>
<ButtonSubmit type="button" fullWidth={false}>
See my option
</ButtonSubmit>
</Link>
</Grid>
</Grid>
</Container>
</Box>
);
};
// ...proptypes and `export` clause
Second example:
// ...react imports omitted...
import makeStyles from '#material-ui/core/styles/makeStyles';
import MuiDialog from '#material-ui/core/Dialog';
const useStyles = makeStyles(() => ({ /* ...styles... */ }));
const Dialog = ({ children, background, backdrop, isOpen, ...rest }) => {
const classes = useStyles({ background });
return (
<MuiDialog
open={isOpen}
maxWidth="sm"
fullWidth
disableBackdropClick
disableEscapeKeyDown
BackdropProps={{
className: backdrop ? classes.backdropBM : classes.backdrop
}}
PaperProps={{
className: classes.paper
}}
scroll="body"
{...rest}
>
{children}
</MuiDialog>
);
};
If you look at the API documentation for almost any of the Material-UI components, you will find at the end of the "Props" section a statement like the following example from Dialog:
Any other props supplied will be provided to the root element (Modal).
This means that any props not explicitly recognized by this component will be passed along eventually to whatever HTML element is the outermost element rendered. So for most Material-UI components, in order to add an id property, you just specify it.
My example below (a modification of the Simple Dialog demo) includes three different ids: one on the Dialog element which will be placed on the outermost div of the Modal, one specified via the PaperProps which will go on the main Paper div of the visible content of the dialog, and one on the Box wrapped around the dialog content.
import React from "react";
import PropTypes from "prop-types";
import { makeStyles } from "#material-ui/core/styles";
import Button from "#material-ui/core/Button";
import Avatar from "#material-ui/core/Avatar";
import List from "#material-ui/core/List";
import ListItem from "#material-ui/core/ListItem";
import ListItemAvatar from "#material-ui/core/ListItemAvatar";
import ListItemText from "#material-ui/core/ListItemText";
import DialogTitle from "#material-ui/core/DialogTitle";
import Dialog from "#material-ui/core/Dialog";
import PersonIcon from "#material-ui/icons/Person";
import Typography from "#material-ui/core/Typography";
import { blue } from "#material-ui/core/colors";
import Box from "#material-ui/core/Box";
const emails = ["username#gmail.com", "user02#gmail.com"];
const useStyles = makeStyles({
avatar: {
backgroundColor: blue[100],
color: blue[600]
}
});
function SimpleDialog(props) {
const classes = useStyles();
const { onClose, selectedValue, open } = props;
const handleClose = () => {
onClose(selectedValue);
};
const handleListItemClick = value => {
onClose(value);
};
return (
<Dialog
onClose={handleClose}
aria-labelledby="simple-dialog-title"
open={open}
PaperProps={{ id: "MyDialogPaperID" }}
id="ThisIDWillBeOnTheModal"
>
<DialogTitle id="simple-dialog-title">Set backup account</DialogTitle>
<Box id="MyBoxID">
<List>
{emails.map(email => (
<ListItem
button
onClick={() => handleListItemClick(email)}
key={email}
>
<ListItemAvatar>
<Avatar className={classes.avatar}>
<PersonIcon />
</Avatar>
</ListItemAvatar>
<ListItemText primary={email} />
</ListItem>
))}
</List>
</Box>
</Dialog>
);
}
SimpleDialog.propTypes = {
onClose: PropTypes.func.isRequired,
open: PropTypes.bool.isRequired,
selectedValue: PropTypes.string.isRequired
};
export default function SimpleDialogDemo() {
const [open, setOpen] = React.useState(false);
const [selectedValue, setSelectedValue] = React.useState(emails[1]);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = value => {
setOpen(false);
setSelectedValue(value);
};
return (
<div>
<Typography variant="subtitle1">Selected: {selectedValue}</Typography>
<br />
<Button variant="outlined" color="primary" onClick={handleClickOpen}>
Open simple dialog
</Button>
<SimpleDialog
selectedValue={selectedValue}
open={open}
onClose={handleClose}
/>
</div>
);
}
Material UI components don't let you set an id for them since the implementation inside should be a black box and may contain multiple html element. See if you can wrap the element in a div and put the id on that instead.
Another option would be to add a class (via the classes prop) to the element instead but I'm not sure if Google Tag Manager can use those instead of ids.

Categories