MaterialUI for React with Styled-Components - reactjs

I want to style the Paper of MaterialUI's Dialog
const StyledDialog = styled(Dialog)`
& .MuiPaper-root {
width: 600px;
}
`;
However, this means that all elements nested inside the Dialog that have the MuiPaper-root class (for example, other Papers) will inherit it.
Is there any way of scoping this styling only to the Paper used by the first Dialog?

There are a several ways to approach this. One approach is to use child selectors (as mentioned in Kaca992's answer), but the Paper is not a direct child of the Dialog so to use this approach you need & > .MuiDialog-container > .MuiPaper-root. Another option is to use Dialog's PaperComponent prop and provide it with a styled Paper component. A third option is to leverage the MuiDialog-paper CSS class.
All three approaches are shown in the example below.
import React from "react";
import Button from "#material-ui/core/Button";
import DialogTitle from "#material-ui/core/DialogTitle";
import Dialog from "#material-ui/core/Dialog";
import Paper from "#material-ui/core/Paper";
import styled from "styled-components";
const StyledDialog = styled(Dialog)`
& > .MuiDialog-container > .MuiPaper-root {
background-color: purple;
}
`;
const StyledDialog2 = styled(Dialog)`
& .MuiDialog-paper {
background-color: blue;
}
`;
const StyledPaper = styled(Paper)`
background-color: green;
`;
export default function SimpleDialogDemo() {
const [open1, setOpen1] = React.useState(false);
const [open2, setOpen2] = React.useState(false);
const [open3, setOpen3] = React.useState(false);
return (
<div>
<Button variant="outlined" color="primary" onClick={() => setOpen1(true)}>
Open dialog using child selectors
</Button>
<Button variant="outlined" color="primary" onClick={() => setOpen3(true)}>
Open dialog using MuiDialog-paper
</Button>
<Button variant="outlined" color="primary" onClick={() => setOpen2(true)}>
Open dialog using custom Paper
</Button>
<StyledDialog
onClose={() => setOpen1(false)}
aria-labelledby="simple-dialog-title"
open={open1}
>
<DialogTitle id="simple-dialog-title">
Paper styled via child selectors
</DialogTitle>
</StyledDialog>
<StyledDialog2
onClose={() => setOpen3(false)}
aria-labelledby="simple-dialog-title"
open={open3}
>
<DialogTitle id="simple-dialog-title">
Paper styled via MuiDialog-paper
</DialogTitle>
</StyledDialog2>
<Dialog
onClose={() => setOpen2(false)}
aria-labelledby="simple-dialog-title"
open={open2}
PaperComponent={StyledPaper}
>
<DialogTitle id="simple-dialog-title">
Paper styled via custom Paper component
</DialogTitle>
</Dialog>
</div>
);
}

Try this:
const StyledDialog = styled(Dialog)`
& > .MuiPaper-root {
width: 600px;
}
`;
css > operator will take only childs that are direct childs of the dialog component. If that is not ok look at other css operators: https://www.w3schools.com/cssref/css_selectors.asp

Related

How to reference a styled component that is in a different dom

I like to add styling to a styled component that is in a different dom.
Like this Material-ui Menu component example, the dashboard button is highlighted gray, and the menu drop is highlighted light blue.
They are written in the same component file but they are in different dom.
I like to add styling to the Menu component from Button component.
Is that possible?
Demo sandbox: https://codesandbox.io/s/si8tr5?file=/demo.js
Menu material ui official doc: https://mui.com/material-ui/react-menu/#basic-menu
index.jsx
import * as React from 'react';
import MenuItem from '#mui/material/MenuItem';
import {DisplayMenu, DisplayButton} from './styles'
export default function BasicMenu() {
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<div>
<DisplayButton
id="basic-button"
aria-controls={open ? 'basic-menu' : undefined}
aria-haspopup="true"
aria-expanded={open ? 'true' : undefined}
onClick={handleClick}
>
Dashboard
</DisplayButton>
<DisplayMenu
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={handleClose}>Logout</MenuItem>
</DisplayMenu>
</div>
);
}
styles.js
import styled from 'styled-components';
import Button from '#mui/material/Button';
import Menu from '#mui/material/Menu';
export const DisplayMenu = styled(Menu)`
padding: 20px;
`;
DisplayMenu.displayName = 'DisplayMenu';
export const DisplayButton = styled(Button)`
margin: 10px;
${DisplayMenu}{
& .MuiPaper-root {
width: 300px;
}
}
`;
DisplayButton.displayName = 'DisplayButton';
I know just doing this below will work but this is just an example and the reality is more complicated.
I just made it simple to ask this question here.
export const DisplayMenu = styled(Menu)`
padding: 20px;
& .MuiPaper-root {
width: 300px;
}
`;
Your current code won't work because you are applying styles to descendent DisplayMenu components (DisplayButton is a sibling). I don't really think it makes sense to do this but you could select the sibling:
export const DisplayButton = styled(Button)`
margin: 10px;
& + ${DisplayMenu}{
& .MuiPaper-root {
width: 300px;
}
}
`;
I think styling DisplayMenu directly makes the most sense (your last approach).
However If this is a permutation of DisplayMenu when used with a button, I think you should consider making the wrapper div into a styled component since that allows you to apply contextual styles to the menu (change its style based on 'where' it was used):
const MenuButton = styled.div`
${DisplayMenu}{
& .MuiPaper-root {
width: 300px;
}
`
// And use this in your component
<MenuButton>
<DisplayButton {...} />
<DisplayMenu {...} />
</MenuButton>
This way we only add the width to DisplayMenu when used within the context of MenuButton

why backgroundColor applies the place where I didn't mean to | Menu component from MUI | styled-components

I set background color pink to the Menu component from mui and this is what I'm seeing when I click dashboard button.
I expected this to add background color to the menu but turned out that half of the page got colored pink.
How can I apply background color to the menu?
import * as React from "react";
import Button from "#mui/material/Button";
import MenuItem from "#mui/material/MenuItem";
import { MenuRaw } from "./styles";
export default function BasicMenu() {
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<div>
<Button
id="basic-button"
aria-controls={open ? "basic-menu" : undefined}
aria-haspopup="true"
aria-expanded={open ? "true" : undefined}
onClick={handleClick}
>
Dashboard
</Button>
<MenuRaw
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={handleClose}>Logout</MenuItem>
</MenuRaw>
</div>
);
}
import styled from "styled-components";
import Menu from "#mui/material/Menu";
export const MenuRaw = styled(Menu)`
width: 412px;
background-color: pink;
`;
You need to specify the class of the menu element that you want to change. In this case you want to overwrite the .MuiPaper-root class of Paper component:
export const MenuRaw = styled(Menu)`
& .MuiPaper-root {
background-color: pink;
width: 412px;
}
`;

I want to style the Button Component with some properties but I see that I can't use classname in updated MUI5

import { styled } from "#mui/system";
import DeleteIcon from "#mui/icons-material/Delete";
import SendIcon from "#mui/icons-material/Send";
import { Button } from "#mui/material";
const Button = styled("button")({
color: "red",
backgroundColor: "black",
padding: "1rem",
});
function App() {
return (
<div>
<Button
variant="contained"
size="medium"
startIcon={<DeleteIcon />}
endIcon={<SendIcon />}
>
Material UI
</Button>
</div>
);
}
export default App;
I think styled is now a new way in MUI to create make and use custom
styles. I don't think I can use className property in this case.
Previously I could use makeStyles and useStyles and assign classname
to the Button component to customize it, How can I use Button
Component from MUI and customize it using styled . Right now I should
define at the top what kind of component is. I want to use Button component, its variant color properties and also customize it using styled.
You can also use sx to add css to components in MUI 5
<Button
sx={{color: "red",
backgroundColor: "black",
padding: "1rem"}}
variant="contained"
size="medium"
startIcon={<DeleteIcon />}
endIcon={<SendIcon />}
>
Material UI
</Button>
you need to use !important to overwrite styles and styled(Button) as it is clear in code. complete version is here in sandbox
import * as React from "react";
import { styled } from "#mui/styles";
import Button from "#mui/material/Button";
import DeleteIcon from "#mui/icons-material/Delete";
import SendIcon from "#mui/icons-material/Send";
const MyButton = styled(Button)({
backgroundColor: "#000 !important",
color: "red !important",
padding: "1rem !important"
});
export default function App() {
return (
<MyButton
variant="contained"
size="medium"
startIcon={<DeleteIcon />}
endIcon={<SendIcon />}
>
Styled Components
</MyButton>
);
}
Try to use the code below
const StyledButton = styled(Button)(() => ({
color: "red",
backgroundColor: "black",
padding: "1rem",
}));
In the first () you need to pass the material ui component as the named export and then you can use the const-name.
So in your code in stead of <Button></Button> you will use the <StyledButton></StyledButton>
Usage:
<StyledButton
variant="contained"
size="medium"
startIcon={<DeleteIcon />}
endIcon={<SendIcon />}
>
Material UI
</StyledButton>
I see a couple of problems here:
you need to make sure that you import as follows:
import { styled } from '#mui/material/styles';
https://mui.com/material-ui/migration/migrating-from-jss/
since you want to customize the mui, pass the Button to styled and rename the component
const CustomButton = styled(Button)({
color: "red",
backgroundColor: "black",
padding: "1rem",
});
Then you can use it
function App() {
return (
<CustomButton
variant="contained"
size="medium"
startIcon={<DeleteIcon />}
endIcon={<SendIcon />}
>
Material UI
</CustomButton>
);
}

Can you add an additional color in Material UI?

I already have a styleguide that I'm trying to implement in Material UI. I can see the Button's color prop takes these options:
| 'default'
| 'inherit'
| 'primary'
| 'secondary'
However I need an additional one:
| 'default'
| 'inherit'
| 'primary'
| 'secondary'
| 'tertiary'
Can you create a new color in Material UI that works with the general theming system? Or is this not really how it's supposed to be used?
UPDATE - This answer was written for v4 of Material-UI. v5 supports custom colors directly and I have added a v5 example at the end.
Though Material-UI does not support this directly in v4, you can wrap Button in your own custom component to add this functionality.
The code below uses a copy of the styles for textPrimary, outlinedPrimary, and containedPrimary but replaces "primary" with "tertiary".
import * as React from "react";
import Button from "#material-ui/core/Button";
import { makeStyles } from "#material-ui/core/styles";
import clsx from "clsx";
import { fade } from "#material-ui/core/styles/colorManipulator";
const useStyles = makeStyles(theme => ({
textTertiary: {
color: theme.palette.tertiary.main,
"&:hover": {
backgroundColor: fade(
theme.palette.tertiary.main,
theme.palette.action.hoverOpacity
),
// Reset on touch devices, it doesn't add specificity
"#media (hover: none)": {
backgroundColor: "transparent"
}
}
},
outlinedTertiary: {
color: theme.palette.tertiary.main,
border: `1px solid ${fade(theme.palette.tertiary.main, 0.5)}`,
"&:hover": {
border: `1px solid ${theme.palette.tertiary.main}`,
backgroundColor: fade(
theme.palette.tertiary.main,
theme.palette.action.hoverOpacity
),
// Reset on touch devices, it doesn't add specificity
"#media (hover: none)": {
backgroundColor: "transparent"
}
}
},
containedTertiary: {
color: theme.palette.tertiary.contrastText,
backgroundColor: theme.palette.tertiary.main,
"&:hover": {
backgroundColor: theme.palette.tertiary.dark,
// Reset on touch devices, it doesn't add specificity
"#media (hover: none)": {
backgroundColor: theme.palette.tertiary.main
}
}
}
}));
const CustomButton = React.forwardRef(function CustomButton(
{ variant = "text", color, className, ...other },
ref
) {
const classes = useStyles();
return (
<Button
{...other}
variant={variant}
color={color === "tertiary" ? "primary" : color}
className={clsx(className, {
[classes[`${variant}Tertiary`]]: color === "tertiary"
})}
ref={ref}
/>
);
});
export default CustomButton;
Then this CustomButton component can be used instead of Button:
import React from "react";
import {
makeStyles,
createMuiTheme,
ThemeProvider
} from "#material-ui/core/styles";
import Button from "./CustomButton";
import lime from "#material-ui/core/colors/lime";
const useStyles = makeStyles(theme => ({
root: {
"& > *": {
margin: theme.spacing(1)
}
}
}));
const theme = createMuiTheme({
palette: {
tertiary: lime
}
});
// This is a step that Material-UI automatically does for the standard palette colors.
theme.palette.tertiary = theme.palette.augmentColor(theme.palette.tertiary);
export default function ContainedButtons() {
const classes = useStyles();
return (
<ThemeProvider theme={theme}>
<div className={classes.root}>
<Button variant="contained">Default</Button>
<Button variant="contained" color="primary">
Primary
</Button>
<Button variant="contained" color="secondary">
Secondary
</Button>
<br />
<Button variant="contained" color="tertiary">
Tertiary
</Button>
<Button color="tertiary">Tertiary text</Button>
<Button variant="outlined" color="tertiary">
Tertiary outlined
</Button>
</div>
</ThemeProvider>
);
}
In v5, the custom button is not necessary. All you need to do is create the theme appropriately:
import React from "react";
import { styled, createTheme, ThemeProvider } from "#material-ui/core/styles";
import Button from "#material-ui/core/Button";
import { lime } from "#material-ui/core/colors";
const defaultTheme = createTheme();
const theme = createTheme({
palette: {
// augmentColor is a step that Material-UI automatically does for the standard palette colors.
tertiary: defaultTheme.palette.augmentColor({
color: { main: lime[500] },
name: "tertiary"
})
}
});
const StyledDiv = styled("div")(({ theme }) => ({
"& > *.MuiButton-root": {
margin: theme.spacing(1)
}
}));
export default function ContainedButtons() {
return (
<ThemeProvider theme={theme}>
<StyledDiv>
<Button variant="contained">Default</Button>
<Button variant="contained" color="primary">
Primary
</Button>
<Button variant="contained" color="secondary">
Secondary
</Button>
<br />
<Button variant="contained" color="tertiary">
Tertiary
</Button>
<Button color="tertiary">Tertiary text</Button>
<Button variant="outlined" color="tertiary">
Tertiary outlined
</Button>
</StyledDiv>
</ThemeProvider>
);
}
Taken from material UI's color palette docs, https://material-ui.com/customization/palette/
A color intention is a mapping of a palette color to a given intention within your application. The theme exposes the following palette colors (accessible under theme.palette.):
primary - used to represent primary interface elements for a user. It's the color displayed most frequently across your app's screens and components.
secondary - used to represent secondary interface elements for a user. It provides more ways to accent and distinguish your product. Having it is optional.
error - used to represent interface elements that the user should be made aware of.
warning - used to represent potentially dangerous actions or important messages.
info - used to present information to the user that is neutral and not necessarily important.
success - used to indicate the successful completion of an action that user triggered.
If you want to learn more about color, you can check out the color section.
So you could probably look into reassigning either of the warn/success/info/error buttons. Generally i would keep the error and warn colors both as red, so the warn palette would be free to reassign for me.

Material UI v1 with React - styling buttons

I'm trying to learn how to use Material UI with React.
I have incorporated v1 of Material UI in my project.
Nothing about coding comes intuitively to me, so I struggle to fill the gaps between the clues left in the documentation for resources.
I know I haven't got the hang of this yet, but piecing together what others have been able to do, I have set up a button in my project, as follows:
import React from 'react';
import Button from 'material-ui/Button';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import { fade } from 'material-ui/styles/colorManipulator';
const MyButton = (props) => {
return <span>
<Button {...props} />
</span>
};
export default MyButton;
I then try to use my button in a couple of places:
import React from 'react';
import MyButton from '../materialui/Button.js';
const style = {
background: '#FF5349',
color: 'white',
padding: '0 30px',
// marginBottom: '30px',
};
const Start = () => (
<span>
<MyButton style={style} size="large">
GET STARTED
</MyButton>
</span>
);
export default Start;
I am trying to change the size of the button.
The Material UI documentation indicates that I should be able to toggle the size property by inserting size="large".
The example given in the documentation is:
<Button size="large" className={classes.button}>
Large
</Button>
I've tried to insert size="large" in the const style in my Start component, in the use of MyButton in the start component and in the Button component itself. None of these attempts do anything to alter the size. The text label in the button looks miniature at the moment and I can't figure out how to manipulate the size.
Can anyone see how to increase the size of the button?
Here is how I have been using it.
You need to set the root Class of the button object (or another available class, refer to the documentation for each available class by components)
import React, { Component } from "react";
import { withStyles } from "material-ui/styles";
import Button from "material-ui/Button";
const styles = theme => ({
button: {
width: "300px",
margin: "0 auto",
textTransform: "uppercase",
padding: "20px 30px",
alignSelf: "center",
},
});
class MyCustomButton extends Component {
render() {
const { classes } = this.props;
return (
<Button color="primary" raised={true} classes={{ root: classes.button }} />
);
}
}
export default withStyles(styles)(MyCustomButton);

Resources