How to make Material-UI's Grid dynamic in height? - css

I'm stuck with a CSS grid issue. I've it in a React application using <Grid /> inMaterial UI with a legend and a data table under it.
The chart, for different students, shows all the courses they have taken during their stay at the university. Number of courses a student has taken can vary from 1 to 40 something. Hence the legend is required to be dynamic in size.
This is the code for the component:
import Grid from '#material-ui/core/Grid';
<Grid item xs={12} className={classes.courseList}>
<Grid container>
{courses.map((e, i) => (
<Grid key={i}>
<Grid container justifyContent="center">
<Button
className={classes.course}
>
<span style={{ color: colorList[i] }}>⬤</span>
{`${i + 1} - ${UpperFirst(e.courseName)}`}
</Button>
</Grid>
</Grid>
))}
</Grid>
</Grid>
I've the following code in my styles.ts for the legend's div:
root: {
flexGrow: 1,
},
courseList: {
height: 120,
borderTop: '1px solid #f2d9f2',
"float": 'left',
},
course: {
padding: '0 4px',
cursor: 'pointer',
border: 'none',
selected: {
backgroundColor: 'white',
},
},
The height in this case is fixed to 120px, which makes the rest of the legend hide behind the data table if data overflows 3 rows.
How can I make it dynamic so that its height can grow/shrink to accommodate large number of dynamic legend data?
Here are two screenshots, first one showing data hidden behind data table, while the second one has width increased to show more data.
More Data Visible On Expansion:

Related

How to make a grid column the same height as the element above it and pushed left

I'm using material UI and I have a grid sitting on top of a Paper element. The first column in the grid is a text input field that I'd to be the same height as the paper and I'd like it pushed left so that it shares the left border with the paper element but I'm not sure how to achieve this affect, I've tried setting 0 margins, changing the position, and messing with the height and width to no affect.
Code pen: https://codesandbox.io/s/laughing-ardinghelli-7cutft?file=/src/App.js
code
import * as React from "react";
import { styled } from "#mui/material/styles";
import Grid from "#mui/material/Grid";
import Paper from "#mui/material/Paper";
import { TextField } from "#mui/material";
export default function ComplexGrid() {
return (
<Paper
sx={{
p: 2,
margin: "auto",
maxWidth: 500,
flexGrow: 1,
backgroundColor: "#1A2027"
}}
>
<Grid container spacing={2}>
<Grid item xs={4} sx={{ alignSelf: "flex-start" }}>
<TextField
id="outlined-basic"
label=""
variant="outlined"
sx={{
backgroundColor: "white",
padding: "0",
flex: 0
}}
/>
</Grid>
<Grid sx={{ alignSelf: "flex-end", color: "white" }} item xs={6}>
<span>test v. test</span>
</Grid>
</Grid>
</Paper>
);
}
edit: I found that if I disable padding-left for all the classes MuiGrid-root.Muigrid-item in inspect element it will push it to the left, but I only want to disable the padding for this first grid item. Overriding it with sx={{paddingLeft: 0}} doesn't seem to do anything
edit2: setting sx={{paddingLeft: "0 !important", paddingTop: "0 !important"}} has gotten the position I wanted, now I just want it to stretch to the size of the paper
The padding: 2 on my paper was the issue, removing this gave me a text input field the same size as my paper

MUI Grid spacing causes grid to have padding left

I am trying to create a grid with a bunch of elements but there seems to be a problem when I add spacing to the elements. Here's a picture with spacing={0} on the Grid container:
Grid container with no spacing
Here's the result when adding spacing :
Grid container with spacing = 3
I am trying to keep the grid the same width as the buttons above (see picture). I tried different solutions but it does not seem to work on my side. Here is my code :
return (
<Grid
sx={{
width: "100vw",
overflowX: "hidden",
padding: { xs: "20px", md: "50px" },
margin: 0,
background: "hsl(0, 0%, 98%)",
}}
container
>
<Grid
sx={{ width: "100%", marginBottom: "30px" }}
item
display="flex"
flexWrap={"wrap"}
justifyContent={"space-between"}
gap={"25px"}
>
<SearchInput />
<FilterMenu />
</Grid>
<Grid container spacing={3} xs={12}>
{countries?.map((country, idx) => (
<Grid item xs={3}>
<CountryCard key={idx} country={country} />
</Grid>
))}
</Grid>
</Grid>
The easiest and correct way in my opinion based on your images, would be to separate your Grid containers. One Grid containing the Search and Filter inputs and another to contain your flags. In this way you can keep a better control of your spacing and use let css customisations in the Grid items. Have a look in this codesandbox where i have left a few comments and let me know it it helps.

Position an element with relative x but absolute y coordinate

I have this layout:
So I have three Material UI Columns in a row, which have different widths I don't know in advance. Now I want to place Button ("Create Item") at the bottom of the screen (absolute), but horizontally centered to the middle (i.e. the main) Column. The content of this middle column can be short, or even more than fits on a screen, and is scrollable in that case.
The problem: The Button positioning does not work.
Placing the Button with a fixed position doesn't center it horizontally at the middle column but the screen.
Placing it at the bottom of the middle column's content with a relative position and textAlign: 'center' messes with the button vertical position (it can even get pushed out of the screen if the middle column's content is too long).
Placing it at the top of the middle column with textAlign: 'center', transform: 'translateY(85vh)' looks only nice until you start scrolling down and you see the Button moving up.
How can I achive this "floating" behavior just regarding the vertical position?
Edit - here's a minimal example:
<Grid container>
<Grid xs={2}>
<Box style={{ textAlign: 'center' }}>
<div>Left Column for Navigation</div>
<div>Nav 1</div>
<div>Nav 2</div>
</Box>
</Grid>
<Grid xs={6}>
<Grid
style={{
zIndex: 9001,
position: 'relative',
textAlign: 'center',
maxHeight: 0,
transform: 'translateY(85vh)',
}}
>
<Button>Create Item</Button>
</Grid>
<Box style={{ textAlign: 'center' }}>
<Grid>Main Column</Grid>
<Grid>Many Items,</Grid>
<Grid>it might even</Grid>
<Grid>require scrolling</Grid>
</Box>
</Grid>
<Grid style={{ textAlign: 'center' }} xs={4}>
<div>Right Column For Context-Related Stuff</div>
<Grid>Context Entry 1</Grid>
<Grid>Context Entry 2</Grid>
<Grid>Context Entry 3</Grid>
</Grid>
</Grid>
In this example, the Button "Create Item" would get scrolled away if there where more items in the main column, but I want it floating at a fixed y-position at the screen.

Making titles of cards have same height

So I have the following situation:
From a certain point on the darkblue color of the boxes just doesn't align anymore. These two boxes are currently being rendered in a flex container. What would be a solution for this problem? I want the upper container to always be aligned with the one next to it. It is also possible that it will be more than 2 components next to each other.
Flex container (material ui Grid component uses Flex)
<Box>
<Grid container>
{resultField.fields?.map((blockField, index) => {
return (
<Grid item xs={12} md={6}>
<DarkValueBox label={blockField.label} value={blockField.value} />
</Grid>
);
})}
</Grid>
DarkValueBox
export const DarkValueBox = ({ label, value, index }) => {
const classes = useStyles();
return (
<Box sx={{ borderRadius: 5 }}>
<Box
sx={{
backgroundColor: "#0A7BB1",
color: "#fff",
px: 2,
py: 3,
borderRight: "1px solid #fff",
}}
>
<Typography fontWeight={600} variant="subtitle1">
{label}
</Typography>
</Box>
<Box sx={{ px: 2, py: 2, border: "1px solid lightgrey" }}>
<Typography variant="subtitle1">
{value}
</Typography>
</Box>
</Box>
);
};
Here's a codesandbox where I recreated the problem:
https://codesandbox.io/s/add-material-ui-forked-ge42z?file=/src/index.js
An approach would be - if you do not want to cut the labels for showing the user as much information as possible - to ensure the blue box is always taking the height of the highest container in the row.
You can do this with adding a wrapper class to the container DarkValueBox with following specification:
wrapper: {
height: "100%",
display: "flex",
flexDirection: "column"
}
Then, tell your box class to take 100%:
box: {
backgroundColor: "darkblue",
border: "1px solid grey",
color: "white",
wordBreak: "break-word", // btw: its `break-word`, not `word-break`
height: "100%"
},
That is it, find it working in a forked sandbox:
https://codesandbox.io/s/add-material-ui-forked-24zg7?file=/src/index.js
Ok, so I was going through your Sandbox and instead of writing the code I decided to point you in the right direction.
You have declared a Grid with material UI which is a type of container similar to FlexBox.
You have not declared a size or width for the box or the containers inside.
Once you set the grid size and wrap direction for the outer 'main' container you will be able to set the sizes for the containers inside, your label boxes.
This will align them.
For the text, there is a 'textOverflow' property which will stop any additional text wrapping over the component and instead replace it with '...'
Material UI Grid - https://mui.com/components/grid/
Textoverflow - CSS: text-overflow: ellipsis with reactJS and IE

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.

Resources