How to arrange Grid for following layout? - css

Overview
I'm attempting to arrange items on the MUI Grid.
There multiple rows and columns which are dynamic
Each row can have a fixed first column and any number of columns after that (Dynamic)
The dynamic part of columns are scrollable wrt each row
Requirement
Since first column of each row is fixed and other columns are scrollable for all rows
_ I want to group these scrollable columns to a single group and implement a single scroll bar
Current
Expected
Current Implementation
{<Grid container>
{rowArray.map(x => (
<>
<Grid item>"Fixed Item"</Grid>
{columnArray.map(x => (
<Grid item>Dynamic items</Grid>
))}
</>
))}
</Grid>}

When splitting your space with Grids, always slice your screen to columns first, then divide each column to some rows.
import { Box, Grid } from "#mui/material";
const fixedItems = [
"row 1's fixed item",
"row 2's fixed item",
"row 3's fixed item",
];
const dynamicItems = [
["row 1 dynamic item 1"],
[
"row 2 dynamic item 1",
"row 2 dynamic item 2",
"row 2 dynamic item 3",
"row 2 dynamic item 4",
"row 2 dynamic item 5",
],
["row 3 dynamic item 1", "dynamic item 2"],
];
const Item = (props) => {
return (
<Box
sx={{
display: "inline-block",
backgroundColor: "cyan",
borderRadius: 2,
textAlign: "center",
width: "300px",
mx: 1,
}}
>
{props.name}
</Box>
);
};
function Test() {
return (
<Box
sx={{
width: "90%",
direction: "ltr",
mx: "auto",
}}
>
<Grid container spacing={1} sx={{ border: "1px solid red" }}>
<Grid
item
xs={3}
container
spacing={1}
sx={{
textAlign: "center",
border: "1px solid yellow",
}}
>
{fixedItems.map((item, index) => (
<Grid item xs={12} key={index}>
<Item name={item} />
</Grid>
))}
</Grid>
<Grid
item
xs={9}
container
spacing={1}
sx={{
overflowX: "scroll",
whiteSpace: "nowrap",
border: "1px solid green",
}}
>
{dynamicItems.map((item, index) => (
<Grid item xs={12} key={index}>
{item.map((innerItem, innerIndex) => (
<Item name={innerItem} key={innerIndex} />
))}
</Grid>
))}
</Grid>
</Grid>
</Box>
);
}
export default Test;

Related

Material UI Paper won't render the correct background color?

I have seen numerous methods in other stackoverflow questions related to how to change the background color of a Material UI Paper component. However, I'm having a strange issue in that the color will change, but not to the correct color?
Here I am trying to make some grids that I will place widgets in. The background is a Paper component which has the same issue. All the paper components rendered do not match the color requested in the code. I have tried changing it with makeStyles() as well as directly with the style attribute:
const useStyles = makeStyles((theme) => ({
widgetPaper: {
backgroundColor: "#233044",
borderRadius: 25
},
}));
...
<Grid container spacing={0} sx={{ mt: "auto", ml: 1, width: "auto" }}>
<Grid
item
container
spacing={0}
xs={3}
align="center"
sx={{ ml: `${props.dw}px`, mt: 2 }}
>
<Grid item xs={6} align="left">
<Paper
sx={{ height: "95%", width: "99%" }}
className={classes.widgetPaper}
>
<Typography> Test1 </Typography>
</Paper>
</Grid>
<Grid item xs={6} align="right">
<Paper
style={{ backgroundColor: "#233044" }}
sx={{ height: "95%", width: "99%", borderRadius: 1 }}
>
<Typography> Test </Typography>
</Paper>
</Grid>
<Grid item xs={6} align="left">
<Paper
style={{ backgroundColor: "#233044" }}
sx={{ height: "95%", width: "99%", borderRadius: 1 }}
>
<Typography> Test </Typography>
</Paper>
</Grid>
<Grid item xs={6} align="right">
<Paper
style={{ backgroundColor: "#233044" }}
sx={{ height: "95%", width: "99%", borderRadius: 1 }}
>
<Typography> Test </Typography>
</Paper>
</Grid>
</Grid>
<Grid
item
xs={7}
align="left"
sx={{ mt: 2, ml: 1, borderRadius: 1 }}
style={{ backgroundColor: "#233044" }}
></Grid>
</Grid>
The layout renders as expected, however the colors of the paper elements are wrong. I know it is the color of the paper elements specifically, because the last grid item doesn't have Paper and it's color is correct:
In case it is relevant; at the App.js level I am using:
const darkTheme = createTheme({ palette: { mode: 'dark' } });
What is it about Paper elements specifically which is causing this? Am I making a really obvious mistake?
Thank you.

React Material UI responsive Grid with Card

I am trying to create a responsive grid layout using cards that should have the same height including an image. I am using React and Material-UI.
I am fiddling around now for hours and cannot come up with a solution. The "flex" part seems super unintuitive to me. Please help.
It is a very small and simple code piece:
const useStyles = makeStyles((theme: Theme) =>
createStyles({
cardGrid: {
flexGrow: 1,
paddingTop: 16,
},
card: {
flex: 1,
height: '100%',
backgroundColor: 'red',
},
cardActionArea: {
flex: 1,
height: '100%',
backgroundColor: 'green',
},
cardMedia: {
height: '0',
paddingTop: '56.25%', // 16:9
},
cardContent: {
flex: 1,
backgroundColor: blue[600],
},
cardContentTitle: {
flex: 1,
backgroundColor: blue[400],
},
cardContentRating: {
backgroundColor: blue[300],
},
cardContentDistance: {
backgroundColor: blue[200],
}
}),
);
// ...
<Container className={classes.cardGrid} maxWidth="xl">
<Grid
container
direction="row"
justify="space-evenly"
alignItems="stretch"
spacing={2}
>
{
dataList.map(data => (
<Grid item
key={`GridItem-${data.id}`} xs={12} sm={6} md={4} lg={2} xl={1}
>
<Card className={classes.card}
onClick={handleCardClick}
key={`OverviewItem-${data.id}`}
>
<CardActionArea className={classes.cardActionArea}>
{
data.previewURL &&
<CardMedia
className={classes.cardMedia}
image={data.previewURL}
title={data.title}
/>
}
<CardContent className={classes.cardContent}>
<Typography gutterBottom variant="h5" className={classes.cardContentTitle}>
{data.title}
</Typography>
<Typography className={classes.cardContentRating}>
Some text
</Typography>
<Typography className={classes.cardContentDistance}>
Some other text
</Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
))
}
</Grid>
</Container>
What I am trying to achieve:
Image should be at the top of each card
"Some text" and "Some other text" should get moved to the bottom
It seems like I have to write "flex:1" and "height:'100%'" multiple times when going down the tree and at some point it breaks completely like in following screenshot:
With the code snippet from above it looks like this:
What is the magic to simply expand the childs of a Grid Item to its maximum height and to still be able to align them as I want.
E.g. the entire card should stretch over the area of the Grid Item and the title part below the image should expand to move the image to the top and "Some text" and "Some other text" to the bottom.
Any hints/ideas are appreciated!
I was able to achieve what I wanted without a Card and without the image. But making the tree bigger and therefore the nesting deeper, breaks everything and I don't understand why.
Here is the simple snippet and the result:
<Container className={classes.cardGrid} maxWidth="xl">
<Grid
container
direction="row"
justify="space-evenly"
alignItems="stretch"
spacing={2}
>
{
toiletOverviews.map(data => (
<Grid item
key={`GridItem-${data.id}`} xs={12} sm={6} md={4} lg={2} xl={1}
>
<Box
display="flex"
flexDirection="column"
style={{height: '100%', backgroundColor: 'purple'}}
>
<Typography
variant="h5"
style={{flex:1, backgroundColor: blue[800]}}
>
{data.title}
</Typography>
<Typography
style={{backgroundColor: blue[600]}}
>
Some text
</Typography>
<Typography
style={{backgroundColor: blue[400]}}
>
Some other text
</Typography>
</Box>
</Grid>
))
}
</Grid>
</Container>
I figured it out! The important part that I did not know is that display:"flex" is only applied to the current element and its direct children. For childrens of its childrens it will not be applied.
The solution now is to correctly apply it to all necessary elements. The sideeffect was that the image was no longer displayed. It had a width/height of zero. The fix here is to add width:"100%" to the CardMedia element.

Using Material-UI's Grid component, how do I get one cell to take up the remaining horizontal width?

I'm trying to use material-ui's Grid component in my React 16.13.0 application. I want to have a row with three items. The first two items should only take up as much space as they need to (I don't want to hard code pixel values if possible). I would like the third item to take up the remaining horizontal space and float the furthest to the rigth (I discovered React doesn't like "float: right" as a style, though). I have this
const styles = (theme) => ({
root: {
textAlign: "left",
margin: theme.spacing(2),
paddingBottom: theme.spacing(1),
color: theme.color.secondary,
},
cardHeader: {
paddingBottom: theme.spacing(0),
},
cardContent: {
width: "100%",
paddingBottom: theme.spacing(1),
},
rowBody: {
width: "100%",
flexWrap: "nowrap",
alignItems: "center",
},
});
...
<CardContent className={classes.cardContent}>
<Grid container className={classes.rowBody}>
<Grid item>
<img height="20" src={require('../../img/apple.svg')} alt="" />
</Grid>
<Grid item>
{title}
</Grid>
<Grid item>
<InfoIcon />
</Grid>
</Grid>
But unfortunately, this renders everything bunched up together
How can I adjust the styles to do what I want?
Edit: This is what is displayed based on the answer given by #Mohsen007 ...
Follow the code below:
rowBody: {
width: "100%",
flexWrap: "nowrap",
alignItems: "center",
display: "flex",
},
<Grid container className={classes.rowBody}>
<Grid item>
<img height="20" src={require('../../img/apple.svg')} alt="" />
</Grid>
<Grid item style={{flex: 1,}}>
{title}
</Grid>
<Grid item>
<InfoIcon />
</Grid>
</Grid>

Material-ui Grid: Grid item's width too big and going outside of Grid container

I am trying to set up a simple layout for a SPA using Material-ui and React. My idea is to have a left hand column as a sidebar and a right-hand main area to render information etc. However, in my current set-up I have two issues:
The <Grid item> and its container <Button> elements extend beyond the left sidebard <Grid container item xs={3} className={classes.sideBarGrid}> into the right hand column. I am not sure what I am doing wrong and any help would be greatly appreciated!
Code Sandbox
Also, I cannot get the right hand grid column <Grid container item xs={9} className={classes.labelGrid}> get to work to be full width, even though I set it to width: "100%".
Code:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import CssBaseline from "#material-ui/core/CssBaseline";
import Typography from "#material-ui/core/Typography";
import Grid from "#material-ui/core/Grid";
import Button from "#material-ui/core/Button";
import TextField from "#material-ui/core/TextField";
const useStyles = makeStyles(theme => ({
mainContainer: {
width: "100vw",
height: "100vh"
},
labelGrid: {
flexGrow: 1,
flexDirection: "column",
backgroundColor: "#EBEDF0",
alignItems: "center",
justifyContent: "center",
width: "100%"
},
sideBarGrid: {
maxWidth: 300,
flexDirection: "column",
justifyContent: "space-between"
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main
},
labelarea: {
margin: theme.spacing(1)
},
imagearea: {
minHeight: 200
},
classButton: {
margin: theme.spacing(1)
},
submit: {
margin: theme.spacing(1)
},
commentField: {
margin: theme.spacing(2, 2, 3)
}
}));
export default function Labelscreen(props) {
const classes = useStyles();
// history for react router
// array with potential classes for image
const buttonText = ["one", "two"];
// function to filter list of labels by property and see if object property is null
return (
<Grid container className={classes.mainContainer}>
<CssBaseline />
<Grid container item xs={3} className={classes.sideBarGrid}>
<Grid item>
{buttonText.map((item, key) => (
<Button
className={classes.classButton}
variant="outlined"
color="primary"
fullWidth
>
{item} ({key + 1})
</Button>
))}
<TextField
id="imageComment"
label="Comment"
placeholder="please put comments here"
multiline
fullWidth
variant="outlined"
value="adfljdaf"
/>
</Grid>
<Grid item>
<Button
type="submit"
fullWidth
variant="contained"
color="secondary"
className={classes.submit}
>
Go back
</Button>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Next
</Button>
</Grid>
</Grid>
<Grid container item xs={9} className={classes.labelGrid}>
<Typography component="h1" variant="h5">
Something
</Typography>
</Grid>
</Grid>
);
}
EDIT
The gray area on the right hand does not fill the whole screen when the screen size is large, even though the width is set to 100% in the labelGrid
Your buttons have margin (right & left), so they move beyond your left sidebar.
You can fix this using:
classButton: {
margin: theme.spacing(1, 0)
},
submit: {
margin: theme.spacing(1, 0)
},
To add back the space on the left&right side you can add padding on the container:
sideBarGrid: {
maxWidth: 300,
flexDirection: "column",
justifyContent: "space-between",
padding: theme.spacing(0, 1)
},

How to Add in items in a column using Flexbox and Material UI

I am looking for some advice as I can't seem to get these items positioned on the modal. I am looking to get add the item counter as text and stars underneath. With the unassigned text at the bottom. I have tried many layouts. This is my code so far:
const styles = theme => ({
root: {
flexGrow: 1,
overflow: 'hidden',
padding: theme.spacing(0, 3),
},
paper: {
maxWidth: 800,
margin: `${theme.spacing(2)}px auto`,
padding: theme.spacing(2),
},
textField: {
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
width: 200,
},
playButton: {
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
"& .rating": {
flex: 1
},
}
});
function Tasks(props) {
const { classes } = props;
return (
<div className={classes.root}>
<Paper className={classes.paper}>
<Grid container spacing={2}>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={2}>
<Grid item xs>
<div className="name-label">
Name
</div>
<Typography variant="h6">
Order cofee beans
</Typography>
<div className="form-divider"></div>
<Typography variant="body2" color="textSecondary">
Process of Description
</Typography>
</Grid>
</Grid>
<Grid item classes={{ root: props.classes.playButton}}>
<Grid item xs={3} className="playButton">
<i class="far fa-play-circle fa-2x"></i>
</Grid>
<div className="workers-assigned-label">
Workers Assigned
</div>
<div>
count / total
</div>
<div className="rating">
Stars go here
</div>
<div>
unassigned
</div>
</Grid>
</Grid>
</Grid>
</Paper>
</div>
);
}
export default withStyles(styles)(Tasks);
I have added an image of a screenshot of the design so that it is clear what I am trying to achieve.
Image: enter image description here
You're going to want something like this, where the flex: 1 is whatever you want to be stretching and taking up any extra space.
const styles = theme => ({
playButton: {
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
position: "relative",
"& .playButton": {
position: "absolute",
top: "80%",
left: "-55px",
transform: "translateY(-50%)",
},
"& .rating": {
flex: 1
}
}
});
const YourComponent = props => (
{...}
<Grid item classes={{ root: props.classes.playButton}}>
<Grid item xs={3} className="playButton">
<i class="far fa-play-circle fa-2x"></i>
</Grid>
<div className="workers-assigned-label">
Workers Assigned
</div>
<div>
count / total
</div>
<div className="rating">
stars go here
</div>
<div>
unassigned
</div>
</Grid>
{...}
);
I suggest you checkout this resource to see what you can do with flex.

Resources