Material-ui breaks down after refresh - reactjs

When i build the project everything looks fine but after i refresh or go to a different page material-ui breaks down and everything looks weird.
Every solution is related to styled-components. I tried adding babel-styled-components but that broke things even more leading to complete non-rendering of material-ui.
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
const useStyles = makeStyles(theme => ({
root:{
justifyContent: 'center'
},
'#global': {
body: {
backgroundColor: theme.palette.common.black,
},
},
button: {
// margin: theme.spacing(20),
margin: 20
},
input: {
display: 'none',
},
}));
function Index() {
const classes = useStyles();
return (
<div style={{justifyContent: 'center'}}>
<Button href={"/"} variant="outlined" color="secondary" className={classes.button}>
home
</Button>
<Button href={"/login"}variant="outlined" color="secondary" className={classes.button}>
Login
</Button>
<Button variant="outlined" color="primary" className={classes.button}>
Dashboard(protected)
</Button>
</div>
);
}
export default Index;
This should render 3 buttons and some spacing between.
At build, it looks how it should be. After refresh the 3 buttons are glued to each other and the spacing is not existent.
https://codesandbox.io/s/material-demo-yp7pv renders it correctly
https://imgur.com/2xTINrw how it looks in browser

Related

How can I put a hover on this Button Style?

These are my codes for the Button. Somehow, background color only works if I do declare the style in the Button itself. Stating the background color in the const useStyles does not work, hence, I only did this. How can I code this where the background color changes when it hover on it?
<Button
variant="contained"
{...otherProps}
className={classes.margin}
style={{ backgroundColor: " #e31837" }}
>
{children}
</Button>
you can use the root property to change your button style (docs), and also change its background on hover:
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: 'red',
'&:hover': {
backgroundColor: 'blue'
}
}
}));
<Button
variant="contained"
{...otherProps}
className={classes.root}
style={{ backgroundColor: " #e31837" }}
>
{children}
</Button>
You can add this to the styles:
'&:hover': {
backgroundColor: ‘red’
}
<Button
variant="contained"
{...otherProps}
className={classes.margin}
onMouseOver={this.toggleHover}
onMouseOut={this.toggleHover}
style={btnStyle}
>
{children}
</Button>
Then add a toggleHover function
toggleHover(){
this.setState({hover: !this.state.hover})
}
Finally on your render function set your style as a variable
let btnStyle = {'backgroundColor: #e31837'};
if (this.state.hover) {
btnStyle = {'backgroundColor: #000000'}
}
You can refer the following code snippet
import React from 'react';
import { createMuiTheme, withStyles, makeStyles, ThemeProvider } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import { green, purple } from '#material-ui/core/colors';
const ColorButton = withStyles((theme) => ({
root: {
color: theme.palette.getContrastText(purple[500]),
backgroundColor: purple[500],
'&:hover': {
backgroundColor: purple[700],
},
},
}))(Button);
export default function CustomizedButtons() {
const classes = useStyles();
return (
<div>
<ColorButton variant="contained" color="primary" className={classes.margin}>
Custom CSS
</ColorButton>
</div>
)
}

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.

Button components inside ButtonGroup

I'm using React 16.9.0 and Material-UI 4.4.2 and I'm having the following issue.
I want to render a ButtonGroup with Button elements inside it but these buttons come from other custom components which return a Button render with a Modal view linked to the button. Thing is, I can't make them look like a ButtonGroup with the same style since it seems like the Button elements only take the "grouping" styling but not the "visual" styling.
Example code to reproduce behaviour:
<ButtonGroup variant="outlined">
<AModal/>
<BModal/>
<CModal/>
</ButtonGroup>
As you can see, the render output does not look as expected. Bare in mind that I'm defining the buttons with the outlined variant since if not they just render as Text Buttons.
Any help is much appreciated
Adding AModal as requested:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import { Button } from '#material-ui/core';
import Modal from '#material-ui/core/Modal';
import Backdrop from '#material-ui/core/Backdrop';
import Fade from '#material-ui/core/Fade';
import InnerModalComponent from './InnerModalComponent';
const useStyles = makeStyles((theme) => ({
modal: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
paper: {
backgroundColor: theme.palette.background.paper,
border: '2px solid #000',
boxShadow: theme.shadows[5],
padding: theme.spacing(2, 4, 3),
},
}));
export default function AModal() {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
function handleOpen() {
setOpen(true);
}
function handleClose() {
setOpen(false);
}
return (
<div>
<Button variant="contained" onClick={handleOpen}> A </Button>
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
className={classes.modal}
open={open}
onClose={handleClose}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{ timeout: 500 }}
>
<Fade in={open}>
<div className={classes.paper}>
<div
style={{
display: 'flex',
flexDirection: 'row',
alignItems: 'stretch',
justifyContent: 'center',
}}
>
<InnerModalComponent/>
</div>
<Button variant="contained" color="secondary" style={{ marginTop: '10px' }}> Button inside Modal</Button>
</div>
</Fade>
</Modal>
</div>
);
}
There are two main issues:
You are adding a div around each of your buttons. This will interfere a little with the styling. Change this to a fragment (e.g. <> or <React.Fragment>) instead.
The way that ButtonGroup works is by cloning the child Button elements and adding props to control the styling. When you introduce a custom component in between, you need to pass through to the Button any props not used by your custom component.
Here is a working example:
import React from "react";
import ReactDOM from "react-dom";
import ButtonGroup from "#material-ui/core/ButtonGroup";
import Button from "#material-ui/core/Button";
import Modal from "#material-ui/core/Modal";
const AModal = props => {
return (
<>
<Button {...props}>A</Button>
<Modal open={false}>
<div>Hello Modal</div>
</Modal>
</>
);
};
const OtherModal = ({ buttonText, ...other }) => {
return (
<>
<Button {...other}>{buttonText}</Button>
<Modal open={false}>
<div>Hello Modal</div>
</Modal>
</>
);
};
// I don't recommend this approach due to maintainability issues,
// but if you have a lint rule that disallows prop spreading, this is a workaround.
const AvoidPropSpread = ({
className,
disabled,
color,
disableFocusRipple,
disableRipple,
fullWidth,
size,
variant
}) => {
return (
<>
<Button
className={className}
disabled={disabled}
color={color}
disableFocusRipple={disableFocusRipple}
disableRipple={disableRipple}
fullWidth={fullWidth}
size={size}
variant={variant}
>
C
</Button>
<Modal open={false}>
<div>Hello Modal</div>
</Modal>
</>
);
};
function App() {
return (
<ButtonGroup>
<AModal />
<OtherModal buttonText="B" />
<AvoidPropSpread />
</ButtonGroup>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Is there a way to create a button with a linear progress within it, using material-ui?

I want to create a button with a built-in linear progress bar. something like this experience, but with Material components:
https://demo.tutorialzine.com/2013/10/buttons-built-in-progress-meters/
I know that there's a way to integrate <CircularProgress/> into a button, is there a way to integrate <LinearProgress/>? it didn't work for me.
Thanks in advance.
Much like the CircularProgress example, which I presume you are referring to this, it's just about getting the CSS correct.
I've forked that example and added a button that has LinearProgress integrated to give you an idea, the relevant code for that example is:
linearProgress: {
position: "absolute",
top: 0,
width: "100%",
height: "100%",
opacity: 0.4,
borderRadius: 4
}
...
<div className={classes.wrapper}>
<Button
variant="contained"
color="primary"
className={buttonClassname}
disabled={loading}
onClick={handleButtonClick}
>
Linear
</Button>
{loading && (
<LinearProgress
color="secondary"
className={classes.linearProgress}
/>
)}
</div>
Something like this:
import React from 'react'
import { makeStyles } from '#material-ui/core/styles'
import Button from '#material-ui/core/Button'
import LinearProgress from '#material-ui/core/LinearProgress'
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
},
button: {
margin: theme.spacing(1),
},
}))
export default function ContainedButtons() {
const classes = useStyles()
return (
<div className={classes.root}>
<Button variant="contained" className={classes.button}>
<div>
Demo
<LinearProgress variant="determinate" value={75} />
</div>
</Button>
</div>
)
}

How to add padding and margin to all Material-UI components?

I need to add padding or margin to some of Material-UI components, but could not find an easy way to do it. Can I add these properties to all components? something like this:
<Button color="default" padding={10} margin={5}>
I know that this is possible using pure CSS and classes but I want to do it the Material-UI way.
You can use de "Spacing" in a BOX component just by importing the component first:
import Box from '#material-ui/core/Box';
The Box component works as a "Wrapper" for the component you want to "Modify" the spacing.
then you can use the next properties on the component:
The space utility converts shorthand margin and padding props to margin and padding CSS declarations. The props are named using the format {property}{sides}.
Where property is one of:
m - for classes that set margin
p - for classes that set padding
Where sides is one of:
t - for classes that set margin-top or padding-top
b - for classes that set margin-bottom or padding-bottom
l - for classes that set margin-left or padding-left
r - for classes that set margin-right or padding-right
x - for classes that set both *-left and *-right
y - for classes that set both *-top and *-bottom
blank - for classes that set a margin or padding on all 4 sides of the element
as an example:
<Box m={2} pt={3}>
<Button color="default">
Your Text
</Button>
</Box>
Material-UI's styling solution uses JSS at its core. It's a high performance JS to CSS compiler which works at runtime and server-side.
import { withStyles} from '#material-ui/core/styles';
const styles = theme => ({
buttonPadding: {
padding: '30px',
},
});
function MyButtonComponent(props) {
const { classes } = props;
return (
<Button
variant="contained"
color="primary"
className={classes.buttonPadding}
>
My Button
</Button>
);
}
export default withStyles(styles)(MyButtonComponent);
You can inject styles with withStyle HOC into your component. This is how it works and it's very much optimized.
EDITED: To apply styles across all components you need to use createMuiTheme and wrap your component with MuiThemeprovider
const theme = createMuiTheme({
overrides: {
MuiButton: {
root: {
margin: "10px",
padding: "10px"
}
}
}
});
<MuiThemeProvider theme={theme}>
<Button variant="contained" color="primary">
Custom CSS
</Button>
<Button variant="contained" color="primary">
MuiThemeProvider
</Button>
<Button variant="contained" color="primary">
Bootstrap
</Button>
</MuiThemeProvider>
In Material-UI v5, one can change the button style using the sx props. You can see the margin/padding system properties and its equivalent CSS property here.
<Button sx={{ m: 2 }} variant="contained">
margin
</Button>
<Button sx={{ p: 2 }} variant="contained">
padding
</Button>
<Button sx={{ pt: 2 }} variant="contained">
padding top
</Button>
<Button sx={{ px: 2 }} variant="contained">
padding left, right
</Button>
<Button sx={{ my: 2 }} variant="contained">
margin top, bottom
</Button>
The property shorthands like m or p are optional if you want to quickly prototype your component, you can use normal CSS properties if you want your code more readable.
The code below is equivalent to the above but use CSS properties:
<Button sx={{ margin: 2 }} variant="contained">
margin
</Button>
<Button sx={{ padding: 2 }} variant="contained">
padding
</Button>
<Button sx={{ paddingTop: 2 }} variant="contained">
padding top
</Button>
<Button sx={{ paddingLeft: 3, paddingRight: 3 }} variant="contained">
padding left, right
</Button>
<Button sx={{ marginTop: 2, marginBottom: 2 }} variant="contained">
margin top, bottom
</Button>
Live Demo
import Box from '#material-ui/core/Box';
<Box m={1} p={2}>
<Button color="default">
Your Text
</Button>
</Box>
We can use makeStyles of material-ui to achieve this without using Box component.
Create a customSpacing function like below.
customSpacing.js
import { makeStyles } from "#material-ui/core";
const spacingMap = {
t: "Top", //marginTop
b: "Bottom",//marginBottom
l: "Left",//marginLeft
r: "Right",//marginRight
a: "", //margin (all around)
};
const Margin = (d, x) => {
const useStyles = makeStyles(() => ({
margin: () => {
// margin in x-axis(left/right both)
if (d === "x") {
return {
marginLeft: `${x}px`,
marginRight: `${x}px`
};
}
// margin in y-axis(top/bottom both)
if (d === "y") {
return {
marginTop: `${x}px`,
marginBottom: `${x}px`
};
}
return { [`margin${spacingMap[d]}`]: `${x}px` };
}
}));
const classes = useStyles();
const { margin } = classes;
return margin;
};
const Padding = (d, x) => {
const useStyles = makeStyles(() => ({
padding: () => {
if (d === "x") {
return {
paddingLeft: `${x}px`,
paddingRight: `${x}px`
};
}
if (d === "y") {
return {
paddingTop: `${x}px`,
paddingBottom: `${x}px`
};
}
return { [`padding${spacingMap[d]}`]: `${x}px` };
}
}));
const classes = useStyles();
const { padding } = classes;
return padding;
};
const customSpacing = () => {
return {
m: Margin,
p: Padding
};
};
export default customSpacing;
Now import above customSpacing function into your Component and use it like below.
App.js
import React from "react";
import "./styles.css";
import customSpacing from "./customSpacing";
const App = () => {
const { m, p } = customSpacing();
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2
style={{ background: "red" }}
className={`${m("x", 20)} ${p("x", 2)}`}
>
Start editing to see some magic happen!
</h2>
</div>
);
};
export default App;
click to open codesandbox
We can use makeStyles or styles props on the Typography component to give margin until version 4.0.
I highly recommend to use version 5.0 of material ui and on this version Typography is having margin props and it makes life easy.
Specific for "padding-top" (10px) using Global style
Read this!
import React from "react";
import { Container, makeStyles, Typography } from "#material-ui/core";
import { Home } from "#material-ui/icons";
const useStyles = makeStyles((theme) => ({
container: {
paddingTop: theme.spacing(10),
},
}));
const LeftBar = () => {
const classes = useStyles();
return (
<Container className={classes.container}>
<div className={classes.item}>
<Home className={classes.icon} />
<Typography className={classes.text}>Homepage</Typography>
</div>
</Container>
);
};
export default LeftBar;
<Button color="default" p=10px m='5px'>
set initial spacing first in the themeprovider i.e the tag enclosing you app entry. It should look like this
import { createMuiTheme } from '#material-ui/core/styles';
import purple from '#material-ui/core/colors/purple';
import green from '#material-ui/core/colors/green';
const theme = createMuiTheme({
palette: {
primary: {
main: purple[500],
},
secondary: {
main: green[500],
},
},
});
function App() {
return (
<ThemeProvider theme={theme}>
<LandingPage />
</ThemeProvider>
);
}
that's it. so add the theme section to the code and use margin/padding as you wish
const theme = {
spacing: 8,
}
<Box m={-2} /> // margin: -16px;
<Box m={0} /> // margin: 0px;
<Box m={0.5} /> // margin: 4px;
<Box m={2} /> // margin: 16px;
you can use "margin" or "m" for short same applies to padding
or
const theme = {
spacing: value => value ** 2,
}
<Box m={0} /> // margin: 0px;
<Box m={2} /> // margin: 4px;
or
<Box m="2rem" /> // margin: 2rem;
<Box mx="auto" /> // margin-left: auto; margin-right: auto

Resources