React - Material UI Grid and useStyles prop issues - reactjs

First time really playing around with materialUI. I've made a grid of cards and sorted out most of the styling within the same component, so I wanted to move all the useStyles styling to a styling file.
After figuring out how to do so, on reload I could see that no backgroundColor styling across any of the components were rendering, but everything else was.
backgroundColor rendered fine when it was in the same file, and weirdly, it renders once (the other backgroundColours not removed render fine, I mean) if I remove one instance of the color and readd it...but on reload, they're all gone again.
Appreciate some help on this please!
GridStyles.js
import { makeStyles } from '#material-ui/core/styles'
const useStyles = makeStyles({
root: {
flexGrow: 1,
marginLeft: '15rem',
marginRight: '15rem',
wordBreak: 'break-all',
whiteSpace: 'unset'
},
containerCard: {
border: 'solid 3px black',
marginRight: '2rem',
marginLeft: '2rem',
marginTop: '3rem',
marginBottom: '5rem',
borderRadius: '8px',
borderLeftStyle: 'dashed',
borderRightStyle: 'dashed',
},
topCard: {
backgroundColor: '#53E9B2',
border: 'none',
boxShadow: 'none',
paddingBottom: '7rem',
position: 'relative'
},
topCardText: {
position: 'absolute',
bottom: 0,
padding: 0,
marginLeft: '2rem'
},
middleCard: {
border: 'solid 2px black',
borderLeftStyle: 'dashed',
borderRightStyle: 'dashed',
backgroundColor: '#53E9B2',
marginRight: '2rem',
marginLeft: '2rem',
marginTop: '1em',
marginBottom: '3rem',
borderRadius: '8px'
},
middleCardText: {
whiteSpace: 'pre-wrap',
color: 'white'
},
bottomCard: {
backgroundColor: '#53E9B2',
border: 'none',
boxShadow: 'none',
paddingBottom: '1rem'
},
bottomCardText: {
color: 'white',
padding: 0,
marginLeft: '2rem'
}
})
export default useStyles
Grid.js
import React from 'react'
import useStyles from './GridStyles'
import {
Grid,
Card,
CardHeader
} from '#material-ui/core/'
const CardGrid = (props) => {
const classes = useStyles(props);
return (
<div className={classes.root}>
<Grid
container
spacing={0}
direction='row'
justifyContent='flex-start'
alignItems='flex-start'
>
{props.cardData.map(elem => (
<Grid
item
xs={4}
sm={4}
md={4}
xl={4}
key={props.cardData.indexOf(elem)}
>
<Card className={classes.containerCard}>
<Card className={classes.topCard}>
<CardHeader className={classes.topCardText} title={elem.name} />
</Card>
<Card className={classes.middleCard}>
<CardHeader
className={classes.middleCardText}
title={`Company Name:\n${elem.company.name}`}
/>
<CardHeader
className={classes.middleCardText}
title={`Company Catchphrase:\n${elem.company.catchPhrase}`}
/>
<CardHeader
className={classes.middleCardText}
title={`Company Bs:\n${elem.company.bs}`}
/>
</Card>
<Card className={classes.bottomCard}>
<CardHeader
className={classes.bottomCardText}
title={`Phone: ${elem.phone}`}
/>
<CardHeader
className={classes.bottomCardText}
title={`Email: ${elem.email}`}
/>
<CardHeader
className={classes.bottomCardText}
title={`Website: ${elem.website}`}
/>
</Card>
</Card>
</Grid>
))}
</Grid>
</div>
)
}
export default CardGrid

Next JS not properly loading Material UI styles until refresh
The accepted answer on this link fixed my problem. Converted the GridStyles page into one const with the styles and nothing else, arrow function with that calls this file with the makeStyles() function reference and it worked.

Related

How to change the border of a specific button when it is clicked using useState in Material UI?

I have three buttons. What I want to achieve is to emphasize an active button(right after it is clicked) by displaying its border color, while the unclicked buttons will remain neutral until they are clicked. Only one button out of the three should be highlighted right after it has been clicked. But currently I am having trouble since it doesn't seem to work on handling the event.
The goal appearance:
source code:
import * as React from "react";
import Button from "#mui/material/Button";
import Stack from "#mui/material/Stack";
export default function TestSample() {
const [selectedIndex2, setSelectedIndex2] = React.useState("");
const handleListItemClick2 = (event, index) => {
setSelectedIndex2(index);
};
return (
<Stack spacing={2} direction="row" sx={{ mt: 3, ml: 5 }}>
<Button
variant="outlined"
sx={{
"&.Mui-selected": {
},
"&.Mui-focusVisible": {
border: "3px solid #F2A42A",
},
":hover": {
border: "3px solid #F2A42A",
},
width: 131,
textTransform: "none",
height: 42,
borderRadius: 3,
fontFamily: "Barlow Condensed",
fontSize: "22px",
}}
selected={selectedIndex2 === 0}
onClick={(event) => handleListItemClick2(event, 0)}
>
Dine In
</Button>
<Button
variant="outlined"
sx={{
"&.Mui-selected": {
border: "3px solid #F2A42A",
},
"&.Mui-focusVisible": {
border: "3px solid #F2A42A",
},
":hover": {
border: "3px solid #F2A42A",
},
width: 131,
height: 42,
textTransform: "none",
borderRadius: 3,
fontFamily: "Barlow Condensed",
fontSize: "22px",
}}
selected={selectedIndex2 === 1}
onClick={(event) => handleListItemClick2(event, 1)}
>
Pickup
</Button>
<Button
variant="outlined"
sx={{
"&.Mui-selected": {
border: "3px solid #F2A42A",
},
"&.Mui-focusVisible": {
border: "3px solid #F2A42A",
},
":hover": {
border: "3px solid #F2A42A",
},
width: 131,
height: 42,
textTransform: "none",
borderRadius: 3,
fontFamily: "Barlow Condensed",
fontSize: "22px",
}}
selected={selectedIndex2 === 2}
onClick={(event) => handleListItemClick2(event, 2)}
>
Delivery
</Button>
</Stack>
);
}
A similar functionality can be found here(but it's React version is outdated compared to mine): https://codesandbox.io/s/white-rain-ye62u?fontsize=14&hidenavigation=1&theme=dark&file=/src/multipleButtons.js
Your responses would indeed help me a lot in my project that I am working, as I am also exploring MUI.
Thank you very much!
Here is a solution using :focus instead of :hover
import "./styles.css";
import MultipleButtons from "./MultipleButtons";
export default function App() {
return (
<div className="App">
<MultipleButtons />
</div>
);
}
I created a ButtonComponent so you don't have all that repeated styles
import * as React from "react";
import Button from "#mui/material/Button";
export default function ButtonComponent({ title }) {
return (
<Button
variant="outlined"
sx={{
"&.Mui-selected": {},
"&.Mui-focusVisible": {
border: "3px solid #F2A42A"
},
":focus": {
border: "3px solid #F2A42A"
},
width: 131,
textTransform: "none",
height: 42,
borderRadius: 3,
fontFamily: "Barlow Condensed",
fontSize: "22px"
}}
>
{title}
</Button>
);
}
And in MultipleButtons
import * as React from "react";
import Stack from "#mui/material/Stack";
import ButtonComponent from "./ButtonComponent";
export default function MultipleButtons() {
return (
<Stack
spacing={2}
direction="row"
justifyContent="space-evenly"
sx={{ mt: 3, ml: 5, p: 3, background: "#1F1D2B" }}
>
<ButtonComponent title="Dine in" />
<ButtonComponent title="Pick up" />
<ButtonComponent title="Delivery" />
</Stack>
);
}

How can I stop my material UI Cards from going off screen creating a horizontal scroll situation?

I have created 5 components that are wrapped inside a component. I want all 5 of those cards to stay in one row whether the screen size increases or decreases. With my current code, the cards show up in one row, but they go over the screen. I would have to scroll to the right in order to see the fifth card.
I want to be able to see all five cards on the screen regardless of the screen size. At the very least, all of them together on a screen larger than an iPad. Please help.
Code Below:
"time-card" component
import * as React from 'react';
import {
Card,
CardHeader,
CardMedia,
CardContent,
Typography,
} from '#mui/material';
import Icon from './images/icon.png';
import { makeStyles } from '#mui/styles';
import { variables } from 'theme';
const useStyles = makeStyles({
card: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
textAlign: 'center',
minWidth: 400,
maxWidth: 500,
height: '100%',
position: 'relative',
backgroundColor: '#7b1f82',
backgroundImage: 'linear-gradient(#891f7e, #6d2386)',
minHeight: '600px',
maxHeight: '700px',
margin: 10,
padding: '30px',
flexGrow: 1,
flexShrink: 1,
},
mediaSize: {
width: 70,
display: 'flex',
alignSelf: 'center',
},
Icon: {
display: 'flex',
alignSelf: 'center',
marginTop: '20px',
boxShadow: `8px 7px 9px 2px #600562`,
borderRadius: '50%',
height: '400',
width: 90,
padding: 7,
},
cardHeader: {
marginBottom: 0,
padding: 0,
},
eventName: {
marginBottom: '15 0',
fontWeight: 600,
fontSize: 70,
align: 'center',
},
cardContent: {
marginTop: 0,
paddingTop: 0,
},
eventBeginTime: {
fontSize: 55,
fontWeight: 600,
},
eventEndTime: {
fontSize: 65,
fontWeight: 600,
},
});
const TimeCard = () => {
const classes = useStyles();
return (
<Card className={classes.card}>
<CardMedia
className={classes.Icon}
component="img"
image={Icon}
></CardMedia>
<CardHeader
flexGrow={1}
className={classes.cardHeader}
title={
<Typography className={classes.eventName} align="center">
Event
</Typography>
}
/>
<CardContent className={classes.cardContent}>
<Typography color={variables.primary.main} variant="h2">
Begins
<Typography className={classes.eventBeginTime}>5:00 AM</Typography>
</Typography>
<Typography color={variables.white} variant="h2">
Ends
<Typography className={classes.eventEndTime}>6:00 AM</Typography>
</Typography>
</CardContent>
</Card>
);
};
export default TimeCard;
"Time-card-grid" component
import * as React from 'react';
import Grid from '#mui/material/Grid';
import { makeStyles } from '#mui/styles';
import TimeCard from './time-card';
const useStyles = makeStyles({
timeCardGrid: {
margin: 0,
},
});
const TimesGrid = () => {
const classes = useStyles();
return (
<div style={{ maxWidth: '100%' }}>
<Grid container className={classes.timeCardGrid} wrap="nowrap">
<TimeCard />
<TimeCard />
<TimeCard />
<TimeCard />
<TimeCard />
</Grid>
</div>
);
};
export default PrayerTimesGrid;
The minWidth property on your card is what's causing the overflow. The card will never be narrower than 400px, which is wider than a lot of phone screens. If you want everything on the page the maxWidth of the card should be the width of the screen divided by 5. e.g maxWidth: '20vw' (20% of the viewport width) or even just width: '20vw' and forget about maximum and minimum.
To do what you want, you have to think about the screen size. For instance,
Each card can't be fixed at 400px. Because otherwise you'll have to run into the situation you got. Maybe remove this line:
minWidth: 400,
And then your TimesGrid can be a flex based. This way all cards can spread out in a row.
const useStyles = makeStyles({
timeCardGrid: {
margin: 0,
display: flex,
justifyContent: "space-between"
},
})

How to correctly align an image inside a React Material ui Grid?

I was working on a footer for my project.
I am using material UI grid for the footer so I wanted to add the logo at the bottom but I don't understand why it is having right padding (I guess it is padding, not sure).
ScreenShot ->
It's something like this. (Have blurred the logo for privacy reasons)
Code Footer.js React Compoennt ->
import React from "react";
import CssBaseline from "#material-ui/core/CssBaseline";
import Typography from "#material-ui/core/Typography";
import { makeStyles } from "#material-ui/core/styles";
import Container from "#material-ui/core/Container";
import Link from "#material-ui/core/Link";
import Grid from "#material-ui/core/Grid";
import Box from "#material-ui/core/Box";
import logoWhite from "../logos/logoWhite.png";
function Copyright() {
return (
<Typography variant="body2" color="textSecondary">
{"Copyright © "}
<Link color="inherit" href="https://material-ui.com/">
Your Website
</Link>{" "}
{new Date().getFullYear()}
{"."}
</Typography>
);
}
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flexDirection: "column",
minHeight: "100vh",
},
main: {
marginTop: theme.spacing(8),
marginBottom: theme.spacing(2),
},
footer: {
padding: theme.spacing(3, 2),
marginTop: "auto",
backgroundColor: "#312D2D",
color: "white",
height: 167,
},
footerGrid: {
width: "20%",
marginLeft: 40,
marginTop: 35,
pading:0,
border: "2px solid red"
},
footerLogo: {
minWidth: "50%",
maxWidth: "60%",
width: "auto",
margin: "0 auto",
backgroundColor: "pink"
},
footerGridLogo: {
width: "fit-content",
pading:0,
borderRight: "1px solid white",
margin:0,
border: "4px solid green"
}
}));
export default function Footer() {
const classes = useStyles();
return (
<div className={classes.root}>
<CssBaseline />
<footer className={classes.footer}>
<Grid spacing={0} className={classes.footerGrid}>
<Grid item className={classes.footerGridLogo}>
<img
src={logoWhite}
alt="brandlogo"
className=""
className={classes.footerLogo}
/>
</Grid>
</Grid>
</footer>
</div>
);
}
Wanted it to look something like this ->
add this inline styling inside the Grid item tag style={{display:'flex',justifyContent:'center',alignItems:'center'}}

How to customize the Material UI Card boxshadow?

I am trying to customize the box shadow for the Card from Material UI. I've tried setting the default boxShadow to none then adding my own style to the cardWrapper I created but this doesn't seem to work. How do you add your own custom boxShadow and is there a way to achieve this without using a div wrapper? Would appreciate help on how to do this, I can't seem to figure it out.
const useStyles = makeStyles({
card: {
paddingTop: 10,
paddingBottom: 25,
paddingLeft: 20,
paddingRight: 20,
boxShadow: "none",
},
cardWrapper: {
shadowColor: "#000",
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.8,
shadowRadius: 2,
elevation: 5,
},
});
<div className={classes.cardWrapper}>
<Card className={classes.card}>
<CardContent>
<Typography className={classes.title} variant="h5" component="h2">
Server Name
</Typography>
</CardContent>
</Card>
</div>
First create styles related to your targeted boxShadow in the useStyle as below:
const useStyles = makeStyles({
root: {
minWidth: 275,
border: "1px solid",
padding: "10px",
boxShadow: "5px 10px red"
},
//other styles and classes//
}
Then apply it to the Card component:
<Card className={classes.root}>
//other parts of your code//
</Card>
sandbox

Use Paper elevation prop via css?

This is probably a bigger design question, but in my material ui app, I have tried to keep all styling done in CSS (using makeStyles), rather than do some styling inside the jsx (as per the material ui docs) and some in CSS.
So far all my styling has worked in css only, but I have hi a sticking point with elevation on the Paper component. I thought it would be a simple case of adding elevation: '3' to my useStyles object (cv__paper), but it only works as below:
//works as expeted
<Paper className={classes.cv__paper} elevation={3}>
<img
className={classes.image}
src={image}
alt=""
></img>
</Paper
//won't style with elevation
<Paper className={classes.cv__paper}>
<img
className={classes.image}
src={image}
alt=""
></img>
</Paper
...
cv__paper: {
elevation: '3'
}
full code
just to confirm, I have checked that the css is being applied (changed the background to blue)
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
root: {
padding: '25px',
maxWidth: '60%'
},
content: {
height: '100%',
width: '100%',
justifyContent: 'center',
textAlign: 'center'
},
image: {
maxWidth: '100%',
maxHeight: '100%'
},
download__icon: {
fontSize: '100px'
},
cv__paper: {
elevation: 3
}
}));
export default useStyles;
const Cv = () => {
const classes = useStyles();
return (
<Container className={classes.root}>
<Box className={classes.content}>
<Paper className={classes.cv__paper} elevation={3}>
<img
className={classes.image}
src={image}
alt=""
></img>
</Paper>
<Link variant="IconButton" href={CvFile} download="mreaybeaton.pdf">
<GetAppIcon className={classes.download__icon}></GetAppIcon>
</Link>
</Box>
</Container>
);
};
Any ideas?
As the docs mention the elevation is a property that gives to Paper shadow depth.
So if you want to add to your Paper elevation style, you must add boxShadow in your className.
Check the below snippet:
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
root: {
padding: '25px',
maxWidth: '60%'
},
content: {
height: '100%',
width: '100%',
justifyContent: 'center',
textAlign: 'center'
},
image: {
maxWidth: '100%',
maxHeight: '100%'
},
download__icon: {
fontSize: '100px'
},
cv__paper: {
boxShadow: "0px 3px 3px -2px rgb(0 0 0 / 20%), 0px 3px 4px 0px rgb(0 0 0 / 14%), 0px 1px 8px 0px rgb(0 0 0 / 12%)"
}
}));
export default useStyles;
const Cv = () => {
const classes = useStyles();
return (
<Container className={classes.root}>
<Box className={classes.content}>
<Paper className={classes.cv__paper} elevation={3}>
<img
className={classes.image}
src={image}
alt=""
></img>
</Paper>
<Link variant="IconButton" href={CvFile} download="mreaybeaton.pdf">
<GetAppIcon className={classes.download__icon}></GetAppIcon>
</Link>
</Box>
</Container>
);
};

Resources