Make Material UI Grid container grow with flexGrow - css

I am creating a chat window where I have my users on the left and my messages on the right.
The thing is I want both columns to grow to the end of the viewport or till the footer but there is no way to make it works. Here is my component.
import Grid from "#material-ui/core/Grid";
const Prueba = () => {
return (
<div style={{ display: "flex" }}>
<Grid container spacing={1} style={{ flexGrow: 2 }}>
<Grid
item
xs={12}
sm={12}
md={4}
lg={3}
style={{ background: "black" }}
></Grid>
<Grid
item
xs={12}
sm={12}
md={8}
lg={9}
style={{ background: "blue" }}
></Grid>
</Grid>
<div
style={{
position: "fixed",
bottom: 0,
height: 100,
width: "100%",
backgroundColor: "red",
}}
></div>
</div>
);
};
export default Prueba;
The container is inside a flex element and the Grid Container has flexGrow property 1. What is not working here?
Here is how it renders now. It's like my Grid container has no height and actually I want it to grow all down to the footer.

You can do this in material-ui with css grid
https://codesandbox.io/s/naughty-yonath-wqr1p?file=/src/App.js
import { styled } from "#material-ui/core";
const Grid = styled("div")({
display: "grid",
gridTemplateColumns: "1fr 3fr",
height: "100vh"
});
const Footer = styled("div")({
position: "fixed",
bottom: 0,
height: 100,
width: "100%",
backgroundColor: "tomato"
});
export default function App() {
return (
<div className="App">
<Grid>
<div style={{ background: "khaki" }}>Left</div>
<div style={{ background: "lightsalmon" }}>Right</div>
</Grid>
<Footer />
</div>
);
}

Related

How to set MUI Slide works correctly with absolute positioned children?

Slide in Material UI transition calculates the dimensions of the component we want to animate, but if the component has children with absolute positioning, their coordinates will not be included in the calculations of the slide animation.
For example in the code below, I would like the transition to end when red box leave the screen, but it ends when parent component (with green border) leave screen
import * as React from "react";
import Box from "#mui/material/Box";
import Switch from "#mui/material/Switch";
import Paper from "#mui/material/Paper";
import Slide from "#mui/material/Slide";
import FormControlLabel from "#mui/material/FormControlLabel";
const ComponentToSlide = (
<Paper
sx={{
m: 1,
width: 100,
height: 100,
position: "relative",
border: "1px solid green"
}}
elevation={4}
>
<Box
sx={{
position: "absolute",
width: 10,
height: 10,
backgroundColor: "red",
top: "-100px"
}}
></Box>
<Box component="svg" sx={{ width: 100, height: 100 }}></Box>
</Paper>
);
export default function SlideFromContainer() {
const [checked, setChecked] = React.useState(false);
const containerRef = React.useRef(null);
const handleChange = () => {
setChecked((prev) => !prev);
};
return (
<Box
sx={{
height: 450,
width: 240,
display: "flex",
padding: 2,
borderRadius: 1,
bgcolor: "grey.100",
overflow: "hidden"
}}
ref={containerRef}
>
<Box sx={{ width: 300 }}>
<FormControlLabel
sx={{ width: 300, marginBottom: "150px" }}
control={<Switch checked={checked} onChange={handleChange} />}
label="Show from target"
/>
<Slide
direction="up"
in={checked}
container={containerRef.current}
timeout={500}
>
{ComponentToSlide}
</Slide>
</Box>
</Box>
);
}
Perhaps the desired result can be achieved using an additional wrapper component for Slide prop container - I have tried this, but doesn't get what I want

how to create an overlay on image with reactJS?

I need to create an overlay that spans the whole image. But I am not sure how to do that.
I tried with relative and absolute positions on CSS. Any way, with CSS or without CSS will do.
Code is available in this playCode.
import React from 'react';
import { Container } from '#mui/material';
import Grid from '#mui/material/Unstable_Grid2';
export function App(props) {
return (
<div className='App'>
<Grid container>
<Grid>
<h1>Do not hide me.</h1>
</Grid>
<Grid>
<Container
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'blue',
}}
>
<img
style={{
maxHeight: 300,
}}
src={
'https://images.unsplash.com/photo-1518133910546-b6c2fb7d79e3?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=735&q=80'
}
alt='img'
></img>
<h1
style={{
position: 'absolute',
left: 0,
top: 0,
opacity: 0.7,
backgroundColor: 'red',
width: 400,
}}
>
Hi there, this text should be only over the image.
</h1>
</Container>
</Grid>
</Grid>
</div>
);
}
// Log to console
console.log('Hello console');
I have played with the code in the provide platform and you can copy the following code and paste it in the playground.
import React from 'react';
import { Container } from '#mui/material';
import Grid from '#mui/material/Unstable_Grid2';
export function App(props) {
return (
<div className='App'>
<Grid container>
<Grid>
<h1>Do not hide me.</h1>
{/*<another image/>*/}
</Grid>
<Grid>
<Container
style={{
display:"flex",
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'blue',
position: "relative"
}}
>
<img
style={{
maxHeight: 300,
}}
src={
'https://images.unsplash.com/photo-1518133910546-b6c2fb7d79e3?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=735&q=80'
}
alt='img'
></img>
<h1
style={{
position: 'absolute',
top: "-21px",
padding: "0 20px",
opacity: 0.7,
height: "100%",
backgroundColor: 'red',
}}
>
Hi there, this text should be only over the image.
</h1>
</Container>
</Grid>
</Grid>
</div>
);
}
// Log to console
console.log('Hello console');
Changes
I have changed style of Container
gave it a position of relative so that the h1 tag's position becomes absolute relative to container and not relative to whole page.
rest of the changes are in visible in h1 tag

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)
},

Make Item go the bottom using Flexbox and Material UI

I am trying to add Unassigned Text to the bottom of my Container, as shown in this mockup:
Below is the code, that I have so far. I am struggling to get the border between the play button working too. I have tried the usual css: bottom:0 and position:relevant Along with Flexbox but it doesn't seem to want to go to the very bottom of the container.
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",
position: "relative",
"& .playButton": {
position: "absolute",
top: "60%",
left: "-55px",
transform: "translateY(-50%)",
},
"& .star-rating": {
"& .fa-star": {
"&:hover": {
"&::before": {
content: "\f005",
color: "yellow"
}
}
}
},
},
});
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" gutterBottom>
{props.name}
</Typography>
<div className="form-divider"></div>
<Typography variant="body2" color="textSecondary">
{props.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>
<Typography variant="h6" gutterBottom>
0/25
</Typography>
<div class="star-rating">
<label class="far fa-star fa-2x"></label>
<label class="far fa-star fa-2x"></label>
<label class="far fa-star fa-2x"></label>
</div>
<div className="dropdown-menu">
<h5>Unnassigned</h5>
</div>
</Grid>
</Grid>
</Grid>
</Paper>
</div>
);
}
export default withStyles(styles)(Tasks);
Any input would be great.
I would recommend starting with a Grid 'skeleton' that looks something like:
<Grid container>
<Grid item container xs={8} direction="column" justify="flex-start">
// Left column contents, with each row as a <Grid item>
</Grid>
<Fab className={classes.fab}><PlayIcon /><Fab>
<Grid item container xs={4} direction="column" justify="space-between" className={classes.right}>
// Right column contents, with each row as a <Grid item>
</Grid>
</Grid>
The direction=column will help you position items vertically within each container. The justify=space-between will ensure that your first item is at the top of the container and your last item (the unassigned text) is at the bottom.
The "right" css class looks like:
right: {
borderLeft: `1px solid ${theme.palette.grey[500]}`,
position: "relative"
}
You can give it a position of "relative" to make it easier to position the fab relative to the column. The "fab" class looks like:
fab: {
position: "absolute",
margin: "auto",
top: 0,
bottom: 0,
left: -28
}
The margin, top, and bottom properties help center the fab vertically, and the left is a bit of a hack based on the dimensions of the fab to center it over the border.
Here's a working draft that brings everything together: https://codesandbox.io/s/tender-torvalds-dlbke?fontsize=14
You can try something like this, or give flex: 1 to anything in the column to make it stretch.
const styles = theme => ({
playButton: {
'& .dropdown-menu': {
marginTop: "auto"
}
}
})

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