#mui grid items of equal height - material-ui

Using the React #mui package, I want to create a grid of items that all stretch to the same height as the tallest item. I've tried searching for similar questions but have not found a working solution, and using #mui v5. Here's my example, also found on Sandbox https://codesandbox.io/s/happy-moon-y5lugj?file=/src/App.js. I prefer a solution (if possible) using the #mui components rather than grid css directly. Also I cannot fix the number of columns, it needs to be responsive.
import * as React from "react";
import {
Box,
Card,
Container,
Grid,
Paper,
Table,
TableBody,
TableRow,
TableCell,
Typography
} from "#mui/material";
export default function App() {
const createTable = (rows) => {
return (
<Table>
<TableBody>
{[...Array(rows).keys()].map((n) => {
return (
<TableRow key={n}>
<TableCell>Aaaaa</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
);
};
return (
<Box p={3}>
<Container maxWidth="sm" height="100%">
<Grid container spacing={2} height="100%">
<Grid item height="100%">
<Paper height="100%" elevation={3} sx={{ p: 3 }}>
<Typography variant="h4">Something</Typography>
{createTable(5)}
</Paper>
</Grid>
<Grid item height="100%">
<Paper height="100%" elevation={3} sx={{ p: 3 }}>
<Typography variant="h4">More things</Typography>
{createTable(3)}
</Paper>
</Grid>
</Grid>
</Container>
</Box>
);
}
This is what I get now. I want the shorter item to be padded on the bottom so its the same height as the first.

Please use this code from the box downwards. You can read more about how to work with grid items on the mui website here.
const StackOverflow = () => {
const createTable = (rows) => {
return (
<Table>
<TableBody>
{[...Array(rows).keys()].map((n) => {
return (
<TableRow key={n}>
<TableCell>Aaaaa</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
);
};
return (
<Box p={3}>
<Container maxWidth="sm">
<Grid container spacing={2}>
<Grid item xs={6}>
<Paper elevation={3} sx={{ p: 3, height: "100%" }}>
<Typography variant="h4">Something</Typography>
{createTable(5)}
</Paper>
</Grid>
<Grid item xs={6}>
<Paper elevation={3} sx={{ p: 3, height: "100%" }}>
<Typography variant="h4">More things</Typography>
{createTable(3)}
</Paper>
</Grid>
</Grid>
</Container>
</Box>
);
};

Something that worked good for me was to use the following in the Papers sx prop:
{{height: "100%", display: "flex", alignItems: "center"}}

Related

MUI dropdown react application

I am using MUI to develop my dashboard.
I am using MUI dropdown component to select the vendor details and there are two options for the Vendor dropdown. i.e "Surya Kumar Yadav", "Eswar". I used the same dropdown in all my cards. When I select the one of the dropdown in any card, it is reflected in all the other cards.
import React from "react";
import {
Box,
Card,
CardContent,
Typography,
Button,
CardActionArea,
CardActions,
Grid,
Select,
MenuItem,
FormControl,
InputLabel,
} from "#mui/material";
import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { HttpClient } from "../http/http";
import { ConfirmDialog, confirmDialog } from "./ConfirmDialog";
const Services = () => {
const [services, setServices] = useState([]);
const [vendors, setVednors] = useState([]);
const [selectedVendor, setSelectedVendor] = useState("");
const PF =
"https://firebasestorage.googleapis.com/v0/b/mern-stack-service-app.appspot.com/o/";
const navigate = useNavigate();
useEffect(() => {
init();
}, []);
const init = () => fetchServices();
const fetchServices = async () => {
const services = await HttpClient.get(`services`);
const vendors = await HttpClient.get(`vendor`);
setVednors(vendors);
setServices(services);
};
const handleChange = (event) => {
setSelectedVendor(event.target.value);
};
console.log(services);
return services.length === 0 ? (
<Grid>
<Typography
sx={{
fontSize: 32,
color: "blue",
display: "flex",
justifyContent: "center",
alignItems: "center",
textDecoration: "underline",
}}
>
Loading your services.....
</Typography>
</Grid>
) : (
<Grid container>
<ConfirmDialog />
<Grid container item xs={12} columnGap={2}>
<Box sx={{ float: "right" }}>
<Button
variant="outlined"
onClick={() => {
confirmDialog("Are you sure want to logout?", () => {
localStorage.clear();
navigate("/login");
});
}}
>
Logout
</Button>
</Box>
</Grid>
<Grid container item xs={12} rowGap={2}>
{services.map((service, index) => (
<Grid item xs={12} sm={6} md={4} key={index}>
<Card>
<CardActionArea>
<CardContent>
<Grid
component="img"
sx={{
height: 150,
width: 350,
maxHeight: { xs: 150, md: 175 },
maxWidth: { xs: 350, md: 375 },
objectFit: "cover",
}}
alt="The house from the offer."
src={
PF +
service.photo +
"?alt=media&token=c19f2d0a-f254-4391-b589-ef7ee3cad9f5"
}
></Grid>
<Grid item xs={12}>
<Typography textAlign="center">
{service.service}
</Typography>
</Grid>
<Grid item xs={12}>
<FormControl sx={{ minWidth: 120 }} size="small" fullWidth>
<InputLabel id="demo-select-small">
Select Vendor
</InputLabel>
<Select
size="small"
labelId="demo-select-small"
id="demo-select-small"
value={selectedVendor}
label="Select Vendor"
onChange={handleChange}
>
{vendors.map((vendor) => (
<MenuItem
key={vendor._id}
value={vendor.name}
id={vendor.name}
>
{vendor.name}
</MenuItem>
))}
</Select>
</FormControl>
</Grid>
</CardContent>
</CardActionArea>
<CardActions>
<Grid item xs={12}>
<Button variant="outlined" color="primary" fullWidth>
Book Service
</Button>
</Grid>
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Grid>
);
};
export default Services;
I want the dropdown action reflect in the selected card.
It's because all of your mapped Select elements get their value from selectedVendor. you can change the code like this using these steps:
First:
Change the selectingVendor useState like this:
const [selectedVendors, setSelectedVendors] = useState([]);
Second:
And the handleChange function
const handleChange = (event,index) => {
const currentSelectedVendors = [...selectedVendors];
currentSelectedVendors[index] = event.target.value
setSelectedVendors(currentSelectedVendors);
};
Third:
You need to change the Select Mui component props.
<Select
size="small"
labelId="demo-select-small"
id="demo-select-small"
value={selectedVendors[index] || ""}
label="Select Vendor"
onChange={(e) => handleChange(e,index)}
>
Although there is another solution for this problem and you can pull <Select> logic out of Services component , I mean it's selectingVendor hook and it's change handler and create a new separate component which handles it.
PS: I think it should be better to use vendor._id as the value prop of your MenuItems

Margin top has no effect

For the code below
import {
TextField,
Stack,
Button,
Box,
Grid,
SvgIcon,
Typography,
Divider,
Link
} from "#mui/material";
// import IconGoogle from "../client/images/google.svg";
export default function Home() {
return (
<Grid container justifyContent="center" padding={20}>
<Grid item>
<Stack spacing={2} width={320}>
<Typography component="label" variant="h5" alignSelf="center">
Sign In
</Typography>
<Button variant="outlined" fullwidth>
{/* <IconGoogle /> */}
Sign in to Google
</Button>
<Divider> OR </Divider>
<TextField variant="outlined" label="Email" fullwidth />
<Stack>
<TextField variant="outlined" label="Password" fullwidth />
<Typography
component="label"
variant="subtitle1"
sx={{ color: "gray", fontSize: 12 }}
>
Minimum 6 Character
</Typography>
</Stack>
<Button variant="contained">Sign In</Button>
<Link component="button" underline="none" sx={{ mt: 100 }}>
Forgot Password
</Link>
</Stack>
</Grid>
</Grid>
);
}
It gives the following screen
which I expect the red rectangle portion to be much larger, since I set sx={{ mt: 100 }}. Why it's not larger and how to rectify it?
If you use padding instead of margin, it does move the button down.
<Link component="button" underline="none" sx={{ pt: 100}}>
Forgot Password
</Link>

Flexgrowth seems not to work wih DataGrid

The size of the main area of the DataGrid changes with the window size but seems to ignore the size required for the page footer (so a scroll bar remains).
export default class DebugDisplay extends Component {
render = () => {
return <Box >
<DataAdapter localDbConnect="items" setAccessor={this.setAccessor}/>
<AppBar position="static">
<Toolbar>
<IconButton color="inherit" aria-label="Menu" onClick={this.toggleMenu}>
<MenuIcon />
</IconButton>
<Typography variant="h6" sx={{flexGrow:1, flexDirection: "row"}}>
POS Web Debug {this.state.timestamp}
</Typography>
</Toolbar>
</AppBar>
<Drawer type="temporary" open={this.state.debugMenuOpen} onClose={this.toggleMenu}>
<Box sx={{display: "flex", flexDirection: "column", flexGrow: 1}}>
<Button onClick={this.toggleMenu}>Close</Button>
<Divider />
<Button onClick={this.testEnter}>Test Enter</Button>
<Button onClick={this.testTotal}>Test Total</Button>
<Button onClick={this.testInvoice}>Test Invoice</Button>
</Box>
</Drawer>
<Paper >
<Button onClick={this.testEnter} variant="outlined">Test Enter</Button>
<Button onClick={this.testTotal} variant="outlined">Test Total</Button>
<Button onClick={this.testInvoice} variant="outlined">Test Invoice</Button>
<DataGrid sx={{display: "flex", flexGrow:1, flexDirection: "column"}} rows={this.state.rows} columns={itemColumns} autoPageSize pagination density="compact" onCellClick={this.onCellClick}/>;
</Paper>
</Box>;
}
What is wrong?

Material UI Grid alignment

How can I align items vertically in material UI?
https://codesandbox.io/s/material-demo-forked-wrn9x
Here I want put Start element and top, Center element at center and End element at bottom
I am looking for clearest and best solution
If you using grid just do this :
<Grid
container
direction="column"
justify="center"
alignItems="center"
spacing={3}
className={classes.container}
>
you can use the interactive tool of MUI doc for play around and get the props you have to pass for create all the layout you need in the future.
https://material-ui.com/components/grid/#grid
Here is the code that will make three grids - start, centre and end to appear in a column one after another. This layout will remain the same across all screen resolutions/breakpoints.
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Grid from '#material-ui/core/Grid';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
paper: {
padding: theme.spacing(2),
textAlign: 'center',
color: theme.palette.text.secondary,
border: '2px solid #969292',
}
}));
export default function CenteredGrid() {
const classes = useStyles();
return (
<div className={classes.root}>
<Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>Start</Paper>
</Grid>
<Grid item item xs={12}>
<Paper className={classes.paper}>Center</Paper>
</Grid>
<Grid item item xs={12}>
<Paper className={classes.paper}>End</Paper>
</Grid>
</Grid>
</div>
);
}
This code will generate a layout like below:

How to move NavLink to the right side in AppBar?

<AppBar position="static" className={this.props.classes.appBar}>
<Toolbar
style={{
margin: "0 auto",
width: "80%"
}}
>
<Link to="/">
<img src={logo} alt="logo" width="65" height="48" />
</Link>
<NavLink
to="/about"
className={this.props.classes.link}
activeClassName={this.props.classes.activeMenu}
>
How can I move NavLink to the right side? I tried with edge, but it does not work. It is only for ImageButton available.
One approach is to use a Grid container and wrap your components in Grid item as follows
<AppBar position="static">
<Toolbar
style={{
margin: "0 auto",
width: "80%"
}}
>
<Grid direction="row" justify="space-between" alignItems="center" container>
<Grid item>
<Link to="/">
<img src={logo} alt="logo" width="65" height="48" />
</Link>
</Grid>
<Grid item>
<NavLink
to="/about"
className={this.props.classes.link}
activeClassName={this.props.classes.activeMenu}
>
// the rest of the code goes here
</Grid>
</Grid>
</Toolbar>
</AppBar>;
The Grid component uses flex and can be configured to work as you need, in your case justify is set to space-between than means that the elements will be pushed to the margin of the container and separated by the space between them.
More on Grid and aligning items can be found in the documentation HERE