Note: I already looked into this question: Cant remove padding-bottom from Card Content in Material UI
But the accepted answer did not fix my issue.
I am using the Material UI React Library attempting to recreate the below image:
I am completely new to using the Material UI, so most of my code will likely not be optimized and probably does not follow best practices. Indeed, I'd be interested to hear how it could be made better.
Here is my code thus far:
<Card className={classes.card}>
<CardActionArea containerStyle={{ paddingBottom: 0 }}>
<CardMedia
className={classes.media}
title="Contemplative Reptile"
image="none"
>
<div className={classes.heading}>
<AccessAlarmIcon className={classes.icon}/>
<Typography className={classes.mainText} variant="h5" component="h2">Delayed</Typography>
<Typography className={classes.subText} variant="subtitle1" component="h5">9:30pm Departure</Typography>
</div>
</CardMedia>
<CardContent className={classes.content}>
<img className={classes.mainPic} src="http://images1.fanpop.com/images/image_uploads/Golden-Gate-Bridge-san-francisco-1020074_1024_768.jpg"></img>
</CardContent>
</CardActionArea>
</Card>
With these styles:
const styles = {
card: {
maxWidth: 300,
},
media: {
height: 60,
backgroundColor: "#FF1547",
padding: 16
},
icon: {
color: "white",
fontSize: 25,
marginRight: 10
},
mainText: {
color: "white",
display: "inline-block",
position: "relative",
top: -3
},
subText: {
color: "white",
marginLeft: 36,
},
heading: {
padding: 0
},
mainPic: {
width: 300,
height: 200,
marginBottom: 0,
padding: 0
},
content: {
padding: "0 !important",
'&:last-child': {
paddingBottom: "0 !important",
},
}
};
This is what it looks like when rendered:
Notice the bottom padding. The Chrome Developer Tools show a 3px bottom padding under the User Agent Stylesheet. I imported a CSS Reset which did not help.
Again, I'm sure that my styles and JSX could be made better, but efficiency, optimization, and elegance were not of my concern.
Thanks,
Jamie
That padding at the bottom is actually caused by the box-shadow styling tied to the "elevation" property of Paper (which Card is based on). Setting the elevation to 0 gets rid of it:
<Card className={classes.card} elevation={0}>
However that also gets rid of the raised look of the card. The correct way to deal with this is to specify the image in a CardMedia element rather than using a separate img tag inside a CardContent element.
<CardMedia
className={classes.mainPic}
image="http://images1.fanpop.com/images/image_uploads/Golden-Gate-Bridge-san-francisco-1020074_1024_768.jpg"
/>
Here's a CodeSandbox showing this:
You can also see this approach used in this demo:
https://material-ui.com/demos/cards/#ui-controls
See if this is what you want. I changed mainPic and content.
This syntax containerStyle={{ paddingBottom: 0 }} does not seem correct even gets the alert in the browser. Maybe you want to change the styleor classes={{root}} of the api CardActionArea.
mainPic: {
width: 300,
marginBottom: 0,
padding: 0,
borderRadius: '0 0 4px 4px',
},
content: {
height: 225,
padding: "0 !important",
'&:last-child': {
paddingBottom: "0 !important",
},
}
Related
I am creating a webpage using mui and and nextjs with typescript. Here I create two separate folder for using mui.
That's why I create a Styles folder-
Single.styles.ts Here I defin my all styles-
export default {
Title: {
fontSize: "18px",
pb: "10px",
mb: "20px",
borderBottom: `1px solid ${theme.palette.primary.border_bottom}`,
position: "relative",
fontWeight: 500,
"&:after": {
content: '""',
position: "absolute",
width: "25%",
bgcolor: "primary.main",
height: "2px",
left: "0",
bottom: "0"
}
},
}
And then I import it in my component I use it-
Single.tsx (Component)
//Styles
import styles from "Styles/Home/SingleTop.styles";
const SingleTop = () => {
return (
<Box>
<Typography variant="h6" component="h6" sx={styles.Title}>
This is title
</Typography>
</Box>
);
};
export default SingleTop;
And it's working perfectly.
Now I am trying to do responsiveness in this webpage. I already search it and I found it-
https://mui.com/material-ui/customization/breakpoints/
From This documentation I am facing two problems. I changes my Single.styles.ts file according to that documentation like this-
const styles = (theme) => ({
Title: {
fontSize: "18px",
pb: "10px",
mb: "20px",
borderBottom: `1px solid ${theme.palette.primary.border_bottom}`,
position: "relative",
fontWeight: 500,
"&:after": {
content: '""',
position: "absolute",
width: "25%",
bgcolor: "primary.main",
height: "2px",
left: "0",
bottom: "0"
},
[theme.breakpoints.up('lg')]: {
}
}
})
export default styles;
And here I found two error. One is type difination for theme. Here How can I define types for this-
const styles = (theme: //Types)=> ({});
My second problem is Where I use this styles in my component by using sx-
sx={styles.Title}
I found this error here-
Property 'Title' does not exist on type '(theme: any) => {}
Please help me how can I solve that problem. How can I apply them perfectly? What is the right way?
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.
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"
},
})
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
There is playground example on Popper component page of material-ui.
To add arrow they use arrowRef.
Please explain me where do they get it from?
You can find the source code of the Material UI Popper "Scroll Playgroud" example here:
https://github.com/mui-org/material-ui/blob/4f2a07e140c954b478a6670c009c23a59ec3e2d4/docs/src/pages/components/popper/ScrollPlayground.js
As you can see, there is some extra styling that you will need to add to your app to display the arrow correctly, because it's not included in the Material UI library itself.
For others looking for a concrete, reusable component that is simple to use like Tooltip but has a more interactive nature like Popper or Popover you can lift and shift the RichTooltip component from the following sandbox I created - it's typescript too. Hope this helps the next person and hides the complexity of arrows for you.
https://codesandbox.io/s/popper-with-arrow-58jhe
For anyone else that needs it, the OP is asking about Material-UI Poppers.
Dmitriy,
Think of React Refs as a variable that always references the element (if rendered) OUTSIDE of the DOM. React best practices are typically to stay out of the DOM if at all possible. There are of course exceptions to this, but it's the rule of thumb.
In this particular instance, it appears that they are creating an element elsewhere and referencing it using the ref so that it can be utilized by the Popper. I found an example of this here. It's a little hard to read through, but the jist is that he creates a span and styles it how he wants to be applied.
MUI v5
Add the modifiers for arrow. Make sure a proper ref is provided.
const [arrowRef, setArrowRef] = useState(null);
<Popper
modifiers={[
{
name: 'arrow',
enabled: true,
options: {
element: arrowRef,
}
}
]}
>
<Box component="span" className="arrow" ref={setArrowRef} />
</Popper>
Add arrow specific styles.
const styles = {
arrow: {
position: 'absolute',
fontSize: 7,
width: '3em',
height: '3em',
'&::before': {
content: '""',
margin: 'auto',
display: 'block',
width: 0,
height: 0,
borderStyle: 'solid',
},
}
};
<Box component="span" className="arrow" ref={setArrowRef} sx={styles.arrow}/>
Add styles for making CSS triangles used by arrow. Make a styled Popper, as Popper doesn't support sx prop.
const StyledPopper = styled(Popper)(({ theme }) => ({ // You can replace with `PopperUnstyled` for lower bundle size.
zIndex: 1,
maxWidth: '375px',
width: '100%',
'&[data-popper-placement*="bottom"] .arrow': {
top: 0,
left: 0,
marginTop: '-0.9em',
width: '3em',
height: '1em',
'&::before': {
borderWidth: '0 1em 1em 1em',
borderColor: `transparent transparent ${theme.palette.background.paper} transparent`,
},
},
'&[data-popper-placement*="top"] .arrow': {
bottom: 0,
left: 0,
marginBottom: '-0.9em',
width: '3em',
height: '1em',
'&::before': {
borderWidth: '1em 1em 0 1em',
borderColor: `${theme.palette.background.paper} transparent transparent transparent`,
},
},
'&[data-popper-placement*="right"] .arrow': {
left: 0,
marginLeft: '-0.9em',
height: '3em',
width: '1em',
'&::before': {
borderWidth: '1em 1em 1em 0',
borderColor: `transparent ${theme.palette.background.paper} transparent transparent`,
},
},
'&[data-popper-placement*="left"] .arrow': {
right: 0,
marginRight: '-0.9em',
height: '3em',
width: '1em',
'&::before': {
borderWidth: '1em 0 1em 1em',
borderColor: `transparent transparent transparent ${theme.palette.background.paper}`,
},
},
}));
Replace the Popper with the above StyledPopper
<StyledPopper
modifiers={[
{
name: 'arrow',
enabled: true,
options: {
element: arrowRef,
}
]}
>
<Box component="span" className="arrow" ref={setArrowRef} />
// rest of the code
</StyledPopper>