Material-UI for react, how layout Card component to align texts - reactjs

So essentially I want to accomplish this block I designed in Adobe XD.
Adobe XD card design
Here is my code to implement the following:
const useStyles = makeStyles({
root: {
minWidth: 275,
maxWidth: 300
},
title: {
fontSize: 14
},
pos: {
marginBottom: 5
}
});
export default function SimpleCard() {
const classes = useStyles();
const bull = <span className={classes.bullet}>•</span>;
return (
<Card className={classes.root}>
<CardContent>
<Typography
className={classes.title}
color="textSecondary"
display="inline"
>
Physics
</Typography>
<Typography display="inline" align="right" style={{ marginLeft: 110 }}>
benevolent
</Typography>
<Typography variant="body2" component="p" align="left">
10/25/2001
</Typography>
</CardContent>
</Card>
);
}
Here is the codepen link:
https://codesandbox.io/embed/material-demo-bi3sm?fontsize=14&hidenavigation=1&theme=dark
The problem with this is that in the first line I have to manually set the distance between the two typography tags. So basically the distance between Physics and Benevolence is set manually. How can I automatically determine that distance? Also How can I get closer to my design?

Flex box can accomplish what you want easily, with the following class:
const useStyles = makeStyles({
header: {
display: "flex",
justifyContent: "space-between"
}
});
And if you use a div to wrap the typography:
<div className={classes.header}>
<Typography
className={classes.title}
color="textSecondary"
display="inline"
>
Physics
</Typography>
<Typography display="inline" align="right">
benevolent
</Typography>
</div>
...
Then it accomplishes what you want.

Have you tried using flexbox? You could put each line in a div and use justify-content with the different "between" options. This would put a set distance between each depending on which option you choose.
These might be the best two options:
justify-content: space-between;
justify-content: space-around;
Also using align-items: center might be good for centering them vertically.
If this doesn't work directly, you might wanna try adding !important to the new CSS code because I know Material-UI is fussy about styling.

Related

Text not aligning properly on MUI card component

I am new to react, I've been following a course and building a demo project. I've tried but for some reason i can't align the price text on a card that has a single line of description. In fact, I want the price to appear on the bottom left of the cards. This is what my code looks like. Any suggestion would be appreciated.
import Card from '#mui/material/Card';
import CardContent from '#mui/material/CardContent';
import CardMedia from '#mui/material/CardMedia';
import Typography from '#mui/material/Typography';
const ItemCard = (props) => {
// return <div className={classes.card}>{props.children}</div>;
return (
<div>
<Card
sx={{
maxWidth: 345,
maxHeight: '100%',
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.25)',
height: '350px'
}}
>
<CardMedia component='img' height='200' image={props.img} alt='icon' />
<CardContent>
<Typography gutterBottom variant='h5' component='div'>
{props.name}
</Typography>
<Typography variant='body2' color='text.secondary'>
{props.description}
</Typography>
<Typography style={{}}>TK. {props.price}</Typography>
</CardContent>
</Card>
</div>
);
};
export default ItemCard;
Please see this image
You can add a min-height css property in your description Typography component like below (make sure the height is enough for fitting two lines. In case you have longer than two lines of description you can add the ellipsis css properties like in this solution):
<Typography variant='body2' color='text.secondary' sx={{minHeight: "30px"}}>
{props.description}
</Typography>
You can do this!
<CardActions>
<Typography style={{}}>TK. {props.price}</Typography>
</CardActions>

Using material-ui's useMediaQuery in Next.js causes style flickering on first rendering

Using #mui/material/useMediaQuery in Next.js causes style flickering on first rendering.
I know this is due to the useMediaQuery value changing between server side and client side.
Is there any way to fix this?
import { useTheme } from '#mui/material/styles';
import useMediaQuery from '#mui/material/useMediaQuery';
...
const theme = useTheme();
const matches = useMediaQuery(theme.breakpoints.down('md'));
...
<Typography variant={matches ? 'subtitle1' : 'h5'}>
{text}
</Typography>
Although this can be easily resolved by specifying display as shown below to switch the display
This verbose writing style should be avoided as much as possible.
<Typography sx={{ display: {xs: 'block', md: 'none'} }} variant={'subtitle1'}>
{text}
</Typography>
<Typography sx={{ display: {xs: 'none', md: 'block'} }} variant={'h5'}>
{text}
</Typography>

Button on card prevent new tab link from launching

I have a card component that has a green button on the top right, an image and text below it, I want to be able to click on anywhere on the card and for it to redirect to the url in the code; however if the green button is clicked, it should do nothing and not open the url. In the code below it doesn't do that, instead it always opens the url. I used href as it allows the left click on mouse to open in the same page, but the middle click to open a new tab while remaining in the same page which is very important.
Here is a link to a codeSandBox having the code: https://codesandbox.io/s/material-demo-forked-chy0d?file=/demo.js
Code:
export default function MediaCard() {
const classes = useStyles();
return (
<Card className={classes.root}>
<a href="sdfs">
<CardActionArea style={{ paddingTop: 50 }}>
<div
style={{
position: "absolute",
color: "white",
top: 8,
right: 8
}}
>
<Button
style={{ background: "green", color: "white" }}
onMouseDown={(e) => e.stopPropagation()}
size="small"
color="primary"
>
BUTTON
</Button>
</div>
<CardMedia
className={classes.media}
image="https://media.tarkett-image.com/large/TH_25121916_25131916_25126916_25136916_001.jpg"
title="Contemplative Reptile"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
jnikn
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
ijneodsk ipknv onfp o nf onopndsfc on pnojnc olpnoinoi hbib iubn
iujno nouno oijipj onoin ioio
</Typography>
</CardContent>
</CardActionArea>
</a>
</Card>
);
try this
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import Card from "#material-ui/core/Card";
import CardActionArea from "#material-ui/core/CardActionArea";
import CardActions from "#material-ui/core/CardActions";
import CardContent from "#material-ui/core/CardContent";
import CardMedia from "#material-ui/core/CardMedia";
import Button from "#material-ui/core/Button";
import Typography from "#material-ui/core/Typography";
const useStyles = makeStyles({
root: {
maxWidth: 345,
position: "relative"
},
media: {
height: 140
// marginTop: 50
}
});
export default function MediaCard() {
const classes = useStyles();
return (
<Card className={classes.root}>
<Button
style={{ zIndex:'1000',
position: "absolute",
top: 8,
right: 8,background: "green", color: "white",width:'70px',height:'30px' }}
onMouseDown={(e) => e.stopPropagation()}
size="small"
color="primary"
>
BUTTON
</Button>
<a href="sdfs">
<CardActionArea style={{ paddingTop: 50 }}>
<CardMedia
className={classes.media}
image="https://media.tarkett-image.com/large/TH_25121916_25131916_25126916_25136916_001.jpg"
title="Contemplative Reptile"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
jnikn
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
ijneodsk ipknv onfp o nf onopndsfc on pnojnc olpnoinoi hbib iubn
iujno nouno oijipj onoin ioio
</Typography>
</CardContent>
</CardActionArea>
</a>
</Card>
);
}

Material-UI Responsive Cards

I'm in the process of testing out Material-UI. I've been using Bootstrap for a long time, but am interested in adapting some React projects to Material-UI. Something I've been trying to figure out is how to create responsive cards in Material-UI. I've leaned pretty heavily on Bootstraps responsive containers in the past, so I can't understand why my cards expand with the page but don't shrink as the window is condensed...If we're meant to write custom css for this I'm cool with that, just need to be pointed in the right direction.
Questions:
Are responsive cards in Material-UI out of the gate a thing?
Or are we meant to write the css to make the cards responsive?
If so, where can I learn to do that? (leaned on Bootstrap a lot in the past)
Thanks in advance for your help!
...
useStyles = () => makeStyles(theme => ({
root: {
flexGrow: 1,
},
paper: {
padding: theme.spacing.unit,
textAlign: "center",
color: theme.palette.text.secondary,
marginBottom: theme.spacing.unit
},
}));
render() {
const {baseData} = this.state;
const {hfcMetrics} = this.state;
const {stateMember} = this.state;
const {stateName} = this.state;
const {states} = this.state;
const {lineVizData} = this.state;
const classes = this.useStyles();
return (this.state.doneLoading === false ? (
<div className={classes.root}>
<Grid container>
<Grid item xs={12}>
<ReactLoading type={"spinningBubbles"} color={"black"} height={'10%'}
width={'10%'} id='spinner'/>
</Grid>
</Grid>
</div>
)
:
(stateMember === true ?
<div className={classes.root}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Card>
<CardHeader
title="Options"
/>
<CardContent style={{ width: '100%', height: 300 }}>
<LineViz
data={lineVizData}
state={stateName}
source='compareTool'
states={states}
vizKey={this.state.vizKey}
/>
</CardContent>
<CardActions>
<Button size="small" color="primary">
Share
</Button>
<Button size="small" color="primary">
Learn More
</Button>
</CardActions>
</Card>
</Grid>
<Grid item xs={6}>
<Card ref={this.elRef}>
<CardHeader
title="Comparison Analysis"
action={
<ButtonGroup variant="text" color="primary" aria-label="text primary button group">
<YearDropDown2
year={this.state.year}
handleChange={this.toggleYear}
/>
<IconButton color='default' component="span"
onClick={() => this.resetStateToggle()}><AutorenewRoundedIcon/></IconButton>
</ButtonGroup>
}
/>
<CardContent style={{padding: 0}}>
<DataCompareTable
data={this.state.compareData}
metric={this.state.metric}
stateName={this.state.stateName}
compareCount={this.state.compareCount}
handleChange={this.toggleStateName}
toggleOne={this.state.toggleOne}
toggleTwo={this.state.toggleTwo}
toggleThree={this.state.toggleThree}
/>
</CardContent>
</Card>
</Grid>
<Grid item xs={6}>
<Paper className={classes.paper}>xs=6</Paper>
</Grid>
</Grid>
</div>
: ''
)
)
}
}
export default CompareTool
Thank you for your question
To answer your questions:
1) not that I know of
2) no you dont have to write alot of css, but yes some css in the usestyles
3) Below I explained in detail the css you have to write, in your code. You are using inline styles and useStyles at the same time, try putting all your styles in the usestyle hook API instead and make it responsive. Hope this helps let me know if I need to make it clearer. Thank you
as far as I know, you can use the "useMediaQuery" hook to make your design responsive.
Here is the component from the material UI Card component page, I only added the useTheme and useMediaQuery imports, and added a medium breakpoint inside useStyle under classes.root Here is a useful link
on "useMediaQuery"
https://material-ui.com/components/use-media-query/#usemediaquery
import { useTheme } from "#material-ui/styles";
import useMediaQuery from "#material-ui/core/useMediaQuery";
const useStyles = makeStyles(theme => ({
root: {
maxWidth: 345,
[theme.breakpoints.down("md")] : {
maxWidth: 200
}
},
media: {
height: 140
}
}));
const Card = () => {
const classes = useStyles();
const theme = useTheme();
const matches = useMediaQuery(theme.breakpoints.up("sm"));
return (
<Card className={classes.root}>
<CardActionArea>
<CardMedia
className={classes.media}
title="Contemplative Reptile"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
Lizard
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
Lizards are a widespread group of squamate reptiles, with over 6,000
species, ranging across all continents except Antarctica
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" color="primary">
Share
</Button>
<Button size="small" color="primary">
Learn More
</Button>
</CardActions>
</Card>
);
}
Hope this helps
You can wrap your card in a container with responsive options or use grids, which is very convenient.

Vertical align using MUI Paper

I want to vertically align some text in a MUI Paper component.
The code is here.
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Typography from '#material-ui/core/Typography';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(3, 2),
height: 200,
verticalAlign: 'middle'
},
}));
function PaperSheet() {
const classes = useStyles();
return (
<div>
<Paper className={classes.root}>
<Typography variant="h5" component="h3">
This is a sheet of paper.
</Typography>
<Typography component="p">
Paper can be used to build surface or other elements for your application.
</Typography>
</Paper>
</div>
);
}
export default PaperSheet;
vertical-align CSS property only works with display: block element.
An option for you could be to declare your root class using flexbox:
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(3, 2),
height: 200,
display: "flex",
flexDirection: "column",
justifyContent: "center"
},
}));
You can use Stack in MUI v5. Set the direction to column and justifyContent to center to center align the content inside the Card:
<Paper component={Stack} direction="column" justifyContent="center">
<div>
This content is vertically aligned
</div>
</Paper>
Live Demo

Resources