How do I align cards in center with MUI? - reactjs

I've created a grid that displays cards using MUI, but the cards are 'stuck' to the left side of the page. I've tried justify='center', mx: 'auto' and alignItems='center' but the cards stay stuck to the left. I'm sure I'm using some prop that overrides my attempts, but I can't find documentation that speaks to my issue. Below is the code:
export default function Home() {
return (
<Box sx={{ flexGrow: 1, mt: 6 }}>
<Grid container spacing={{ xs: 2, md: 3 }} columns={{ xs: 4, sm: 8, md: 12 }}>
{Array.from(Array(6)).map((_, index) => (
<Grid item xs={2} sm={4} md={4} key={index}>
<ProductCard />
</Grid>
))}
</Grid>
</Box>
);
}
Below is what React is rendering.

you can to in grid like this:
<Grid item xs={2} sm={4} md={4} key={index} alignItems="center" justify="center">
<ProductCard />
</Grid>

Related

Grid item not shrinking to fit the contained Scrollable List

I am trying to get the grid item containing the scrollable list to shrink so the back button is just below the list.
Following is the code, and a link to CodeSandbox. There is a lot of grid and box components surrounding the list. These are extracts from other parent components so I get it all in one file for simplicity.
https://codesandbox.io/s/y2c9sn?file=/src/App.js
import * as React from "react";
import {
Box,
Button,
Grid,
List,
ListItem,
ListItemText,
ListItemButton,
AppBar,
Toolbar,
Typography,
} from "#mui/material";
const usersList = [
"user1",
"user2",
"user3",
"user4",
"user5",
"user6",
"user7",
"user8",
"user9",
"user10",
];
function App() {
return (
<Box
sx={{
display: "flex",
justifyContent: "center",
height: "100vh",
}}
>
<Grid container justifyContent="center">
<Grid item xs={12} md={8}>
<AppBar position="static">
<Toolbar>
<Typography variant="h6">Scrollable List</Typography>
</Toolbar>
</AppBar>
</Grid>
<Grid item xs={12} md={8}>
<Box>
<Grid container justifyContent="center">
<Grid item xs={12}>
<List sx={{ maxHeight: "50%", overflow: "auto" }}>
{usersList.map((user, index) => {
return (
<ListItem disablePadding key={index}>
<ListItemButton>
<ListItemText>{user}</ListItemText>
</ListItemButton>
</ListItem>
);
})}
</List>
</Grid>
</Grid>
<Grid container justifyContent="center">
<Grid item xs={8}>
<Button
name="back"
variant="contained"
color="primary"
value="back"
fullWidth
size="small"
>
Back
</Button>
</Grid>
</Grid>
</Box>
</Grid>
</Grid>
</Box>
);
}
export default App;
Link to CodeSandbox
https://y2c9sn.csb.app/
You can move this style:
sx={{ maxHeight: "50%", overflow: "auto" }}
from your List component to its first parent Grid container.
This sandbox is the updated version of your sandbox with this change.

Having grid items display based on their size MUI Quilted Grid Layout

Image of Issue
Apologies for the zoomed out image, but I am using MUI in React to display a bunch of nested cards dynamically (The data has nested components rendering other components).
Each grid has cards that has grids within them and cards within the grids. I am trying to have the cards fit the page.
So in the image below, I would like the grid component on the second row and second column to come up to where the grid component on the first row second column ends.
I've been searching around trying to find the answer this question but a newbie to frontend so I am not sure how to phrase it. Any advice would be helpful!
Edit:
I am curious about making a quilted grid layout
const useStyles = makeStyles({
gridContainer: {
paddingLeft: "85px",
paddingRight: "85px",
},
root: {
minWidth: 200,
},
bullet: {
display: "inline-block",
margin: "0 2px",
transform: "scale(0.8)",
},
title: {
fontSize: 14,
},
pos: {
marginBottom: 12,
},
parentFlexRight: {
display: "flex",
justifyContent: "flex-end",
},
leftAlignItem: {
marginRight: "auto",
marginTop: "auto",
},
stretch: { height: "100%" },
item: {
display: "flex",
flexDirection: "column",
},
});
var checkIndex = 0;
const renderCourseRequirements = (RequiredCourses) => {
return (
<Grid
container
spacing={0}
direction="column"
alignItems="center"
justifyContent="center"
>
{RequiredCourses.map((course, index) => {
var Index = checkIndex;
checkIndex = checkIndex + 1;
return (
<Grid key={index} item xs={12} sm={6} md={4}>
<Card sx={{ width: 200 }} variant="outlined">
<CardContent>
<Typography color="textSecondary" gutterBottom>
{course}
</Typography>
<Checkbox
id={`custom-checkbox-${Index}`}
name={course}
value={course}
checked={checkedState.includes(course)}
onChange={() => handleOnChange(course)}
/>
</CardContent>
</Card>
</Grid>
);
})}
</Grid>
);
};
const renderComponents = (components) => {
return (
<Grid
container
spacing={0}
direction="column"
alignItems="center"
justifyContent="center"
>
{components.map((component, index) => {
return (
<Grid
container
spacing={0}
direction="column"
alignItems="stretch"
justifyContent="center"
key={index}
item
xs={12}
sm={6}
md={4}
>
<Card className={classes.root} variant="outlined">
<CardContent>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
{component.component_name}
</Typography>
<Typography className={classes.pos} color="textSecondary">
Required Number of Courses: {component.required_num_courses}
</Typography>
{renderCourseRequirements(component.course_list)}
</CardContent>
</Card>
</Grid>
);
})}
</Grid>
);
};
const renderComponentFamilies = (componentFamilies) => {
return (
<Grid container spacing={4} className={classes.item}>
{componentFamilies.map((componentFamily, index) => {
if (componentFamily.component_list.length > 1)
return (
<Grid key={index} xs={8} sm={6} md={4}>
<Card className={classes.stretch} variant="outlined">
<CardContent>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
{componentFamily.component_family_name}
</Typography>
<Typography className={classes.pos} color="textSecondary">
Required Number of Components :{" "}
{componentFamily.required_num_components}
</Typography>
{renderComponents(componentFamily.component_list)}
</CardContent>
</Card>
</Grid>
);
return (
<>
<Grid key={index} item xs={12} sm={6} md={4}>
{renderComponents(componentFamily.component_list)}
</Grid>
</>
);
})}
</Grid>
);
};
A couple of resources that may point you in the right direction. Setting some CSS breakpoints may also work with your content.
https://mui.com/system/sizing/
https://mui.com/material-ui/customization/default-theme/?expand-path=$.breakpoints.values
If that's not what you're looking for, I'd recommend wrapping your elements in an element that references a method with a 'resize' event listener that makes your preferred changes after the resize is triggered.

How can I automatically import an icon which fetches from the server in NextJS?

I want to dynamically generate a page in the Next-JS app. Inside this page should be imported automatically Icons which fetches from the server Instead of writing it statically:
{
"id": 1,
"title": "Budget",
"value": "$24K",
"persent" :"12%",
"duration" :"Since Last Month",
"icon":"MoneyIcon",
"rise":"false"
},
in this timeMoneyIcon from Material-UI.
In this case, was used map method in order to render fetched data.
How can I put this fetched icon name as a tag same as <MoneyIcon/> in the component?
{posts.map((post) => (
<>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<Card sx={{ height: "100%" }}>
<CardContent>
<Grid container spacing={3} sx={{ justifyContent: "space-between" }}>
<Grid item>
<Typography color="textSecondary" gutterBottom variant="overline">
{post.title}
</Typography>
<Typography color="textPrimary" variant="h4">
{post.value}
</Typography>
</Grid>
<Grid item>
<Avatar
sx={{
backgroundColor: "error.main",
height: 56,
width: 56,
}}
>
**<MoneyIcon />**
</Avatar>
</Grid>
</Grid>
<Box
sx={{
pt: 2,
display: "flex",
alignItems: "center",
}}
>
<ArrowDownwardIcon color="error" />
<Typography
color="error"
sx={{
mr: 1,
}}
variant="body2"
>
{post.persent}
</Typography>
<Typography color="textSecondary" variant="caption">
{post.duration}
</Typography>
</Box>
</CardContent>
</Card>
</Grid>
</>
))}
If I understand you correctly you are trying to pass the MUI Icon to the Component and render the icon. For that you can simply pass the Icon as a value of your object wrapped in a React Fragment.
import AccountBalanceIcon from '#mui/icons-material/AccountBalance';
const myObject = {
id: 1,
value: "24K",
icon: <><AccountBalanceIcon/></>
)};
export default function MyComponent(props) {
return(
<div>
<span>{myObject.value}</span>
{myObject.icon}
<div>
)
}
You can import them dynamically by name for example you can fetch the Icon name from server then in the page do this:
import * as MuiIcons from '#mui/icons-material'
function YourPage({IconName}){
const IconComponent = MuiIcons[IconName]
return <Grid container>
<IconComponent />
</Grid>
}
and if you want for example #mui/icons-material/Memory the Icon name is "Memory".
But I think this approach is not treeshakable you may bring the entire jungle , I am not sure about that though, you should check the bundle after compiling.

How can I fix the columns of the dynamic card?

How can I make the card appear where there are 2 columns for the 1st card and then another 2 columns far the second card? So for, this is what it shows.
but I wanted it to look like this:
these are my codes for the styling:
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
padding: theme.spacing(2),
},
media: {
height: 300,
},
}));
and these are my codes for the card:
<div className={classes.root}>
<Grid
container
spacing={12}
direction="row"
justify="flex-start"
alignItems="center"
>
{data.map((elem) => (
<Grid item xs={12} sm={6} md={3} key={data.indexOf(elem)}>
<Card>
<CardHeader title={name} subheader={desc} />
<CardMedia
className={classes.media}
image={img}
title={name}
/>
</Card>
</Grid>
))}
</Grid>
</div>
It seems like the cards are stretched to full width, which prevents them from sharing the same flex-row.
There are lots of possible solutions to this. One could be to set a max-width on the cards so they don't fill the whole row. That way they would have space to sit besides each other like in your example.

How do I organise 5 items evenly in a row with material-ui's grid system?

The grid system is 12, how can I evenly put 5 items in a row? 2.4 doesn't work... Thanks in advance :)
my code:
<Grid container spacing={10}>
{data.map(item => (
<Grid item xs={12} md={2.4}>
<div style={{ fontWeight: "700", textTransform: "capitalize" }}>
{item}
</div>
</Grid>
))}
</Grid>
See the Auto Layout section from the docs for an example of how to do this.
For your code, I believe the following should work:
<Grid container spacing={10}>
{data.map(item => (
<Grid item xs={12} md> // should also add a "key" prop here
<div style={{ fontWeight: "700", textTransform: "capitalize" }}>
{item}
</div>
</Grid>
))}
</Grid>
You can try adding <Grid lg={12/5}></Grid. this case works if you want to show 5 elements in one row
Make your Grid container flex direct to raw and give each item xs={2} for all of them to fit, also you can add some spacing and center elements to container itself. In case you want each item be bigger then 2, consider wrap the row in a ScrollY custom component
<Grid container spacing={1} direction="row" justify="center" alignItems="center" >
{data.map(item => (
<Grid item xs={2}}>
<div style={{ fontWeight: "700", textTransform: "capitalize" }}>
{item}
</div>
</Grid>
))}
</Grid>
// optional ScrollY wrapper, use like <ScrollY> {data.map ...}</ScrollY>
const ScrollY = (props) =>
<div style={{overflowX:'hidden', overflowY: 'scroll',dispaly:'none', height: '80%'}}>
{props.children}
</div>

Resources