mui component props, set responsively - reactjs

I don't want to manipulate the basic style of material-ui but I want to change some value of some components props responsively by breakpoints.
For example:
How can I responsively set the <TextField/>'s size prop?
I want to do it inline.
I know other methods like: styled(), css,...
import { Grid, IconButton, styled, TextField } from "#mui/material";
import React from "react";
import SearchIcon from "#mui/icons-material/Search";
import { ThemeContext } from "#emotion/react";
let TextFieldS=styled(TextField)({
'& fieldset': {
borderRadius: 35,
},
})
export default function SearchBox() {
return (
<Grid container spacing={1}>
<Grid item xs="auto">
<IconButton>
<SearchIcon color="primary" fontSize="large" />
</IconButton>
</Grid>
<Grid item xs>
<TextFieldS
label="جستجو در تمام محصولات"
type={"search"}
variant="outlined"
fullWidth
//------> size={{[theme.breakpoint.down('md')]:'small'}}
/>
</Grid>
</Grid>
);
}

import { Grid, IconButton, styled, TextField } from "#mui/material";
import React from "react";
import SearchIcon from "#mui/icons-material/Search";
import { ThemeContext } from "#emotion/react";
import useMediaQuery from '#mui/material/useMediaQuery';
import { useTheme } from '#mui/material/styles';
let TextFieldS=styled(TextField)({
'& fieldset': {
borderRadius: 35,
},
})
export default function SearchBox() {
const theme = useTheme();
const mdOnly = useMediaQuery(theme.breakpoint.down('md'));
return (
<Grid container spacing={1}>
<Grid item xs="auto">
<IconButton>
<SearchIcon color="primary" fontSize="large" />
</IconButton>
</Grid>
<Grid item xs>
<TextFieldS
label="جستجو در تمام محصولات"
type={"search"}
variant="outlined"
fullWidth
//------> size={mdOnly ? 'medium': 'small'}
/>
</Grid>
</Grid>
);
}

Related

How to pass props to a component being "styled" in MUI?

Learning MUI and following the docs pretty well. However, I'm trying to style the Paper component as in the examples, but I want the Paper component to have elevation={3}.
How do I pass that prop to Paper in the below code?
import * as React from 'react';
import { styled } from '#mui/material/styles';
import Box from '#mui/material/Box';
import Paper from '#mui/material/Paper';
import Grid from '#mui/material/Unstable_Grid2';
const Item = styled(Paper)(({ theme }) => ({
backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
...theme.typography.body2,
padding: theme.spacing(1),
textAlign: 'center',
color: theme.palette.text.secondary,
}));
export default function BasicGrid() {
return (
<Box sx={{ flexGrow: 1 }}>
<Grid container spacing={2}>
<Grid xs={8}>
<Item>xs=8</Item>
</Grid>
<Grid xs={4}>
<Item>xs=4</Item>
</Grid>
<Grid xs={4}>
<Item>xs=4</Item>
</Grid>
<Grid xs={8}>
<Item>xs=8</Item>
</Grid>
</Grid>
</Box>
);
}
You can pass the prop and access it. within the Styled component. Remember these are mostly passed as HTML attributes so boolean works a little differently as a string.
Here's a working example at Codesandbox. You can check how we have added a border to the item based on the prop.
import * as React from "react";
import ReactDOM from "react-dom";
import { styled } from "#mui/material/styles";
import Box from "#mui/material/Box";
import Paper from "#mui/material/Paper";
import Grid from "#mui/material/Unstable_Grid2";
function App() {
return (
<Box sx={{ flexGrow: 1 }}>
<Grid container spacing={2}>
<Grid xs={8}>
<Item border={"true"}>xs=8</Item>
</Grid>
<Grid xs={4}>
<Item>xs=4</Item>
</Grid>
<Grid xs={4}>
<Item>xs=4</Item>
</Grid>
<Grid xs={8}>
<Item>xs=8</Item>
</Grid>
</Grid>
</Box>
);
}
const Item = styled(Paper)(({ theme, border }) => ({
backgroundColor: theme.palette.mode === "dark" ? "#1A2027" : "#fff",
...theme.typography.body2,
padding: theme.spacing(1),
textAlign: "center",
border: border === "true" ? "1px solid red" : "none",
color: theme.palette.text.secondary
}));
ReactDOM.render(<App />, document.querySelector("#app"));

My react Material UI buttons aren't rendering

I've written the same code everywhere but it doesn't render my buttons. It does render but is not visible. The button are present between the logo and the search input.
There aren't any errors nor build fail to debug the problem.
I tried copying and pasting the code from the second too!
import React from "react";
import { Link } from "react-router-dom";
import { Box, Container, ThemeProvider, Input, useScrollTrigger, Slide, AppBar, Toolbar } from '#mui/material'
import { Button } from "#mui/material";
import customTheme from "./Theme"
function HideOnScroll(props) {
const { children, window } = props;
const trigger = useScrollTrigger({
target: window ? window() : undefined,
});
return (
<Slide appear={false} direction="down" in={!trigger}>
{children}
</Slide>
);
}
const ariaLabel = { 'aria-label': 'description' };
function Navigation(props) {
return (
<Container>
<ThemeProvider theme={ customTheme }>
<HideOnScroll>
<AppBar color={"primary"}>
<Toolbar>
<Box m={1} p={1}>
<Link to=""><img src="/static/brand-logo.svg" alt="brand-logo" /></Link>
</Box>
<Box m={1} p={1}>
<Button variant="outlined" style={{ borderRadius: 20 }} href="/">Home</Button>
<Button variant="outlined" style={{ borderRadius: 20 }} href="/blog">Blogs</Button>
<Button variant="outlined" style={{ borderRadius: 20 }} href="/create-blog">Create</Button>
</Box>
<Box m={1} p={1}>
<Input color={"secondary"} placeholder="Can't search :)" inputProps={ariaLabel} />
</Box>
</Toolbar>
</AppBar>
</HideOnScroll>
<Toolbar />
</ThemeProvider>
</Container>
);
}
export default Navigation;
Another button code which works
import React from "react";
import { Grid, Divider, Typography, Button } from "#mui/material";
import InstagramIcon from '#mui/icons-material/Instagram';
import LinkedInIcon from '#mui/icons-material/LinkedIn';
import GitHubIcon from '#mui/icons-material/GitHub';
export default function Home(props) {
return(
<Grid container spacing={4} justifyContent="center" alignItems="center" color={"primary"}>
<Grid item xs={12} sm={6} lg={4}>
<Typography variant="h1" component="div" gutterBottom>A painting of my life.</Typography>
<Button size="large" variant="outlined" style={{ borderRadius: 50, fontSize: 40 }} href="/blog">Peek My Diary</Button>
</Grid>
</Grid>
);
}

I wanna to add a little gap on two TextField in Material-UI

Here is my js file, I wanna add a little gap between them like padding. Many people are using box property to declare margin and padding but I don't know why I can't use the box property perfectly. If I use box property like ml={1} then the TextField is upside down. Don't forget the most important part is I wanna use this on a class component, not on a functional component.
<Grid item
xs={12}
sm={6}
md={6}
lg={6}
xl={6}>
<TextField label="Name"
variant="outlined"
color="primary"
size="small"
autoFocus />
<TextField label="Address"
variant="outlined"
color="primary"
size="small"
multiline
rowsMax={1} />
</Grid>
One of the ways to solve is using makeStyles. I have given the complete code. Please review. I have referred to Material UI: Use theme in React Class Component sample for Class Component.
Complete Code using Function Component:
import './App.css';
import React from 'react';
import Grid from '#material-ui/core/Grid';
import { TextField } from '#material-ui/core';
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
control: {
padding: theme.spacing(2),
},
}));
const App = () => {
const classes = useStyles();
return (
<div className="App">
<h1>Hello MERN !!</h1>
<br />
<Grid item xs={12} sm={6} md={6} lg={6} xl={6}>
<TextField label="Name"
className={classes.control}
variant="outlined"
color="primary"
size="small"
autoFocus />
<TextField label="Address"
variant="outlined"
className={classes.control}
color="primary"
size="small"
multiline
rowsMax={1} />
</Grid>
</div >
);
}
export default App;
Complete Code using Class Component:
import React from 'react';
import Grid from '#material-ui/core/Grid';
import { TextField } from '#material-ui/core';
import { withStyles } from "#material-ui/core/styles";
const styles = theme => ({
root: {
padding: theme.spacing(2),
}
});
class Car extends React.Component {
render() {
const { classes } = this.props;
return (
<>
<Grid item xs={12} sm={6} md={6} lg={6} xl={6}>
<TextField label="Name"
variant="outlined"
className={classes.root}
spacing={3}
color="primary"
size="small"
autoFocus />
<TextField label="Address"
variant="outlined"
className={classes.root}
spacing={3}
color="primary"
size="small"
multiline
rowsMax={1} />
</Grid>
</>
);
}
}
export default withStyles(styles, { withTheme: true })(Car);
Make sure your Grid item property in a Grid container.You have to wrap the Grid item property in a Grid Container Property.

Create a grid with variable card heights using material-ui react

I am trying to create a grid similar to this website by using Material-UI. However when the height of one card changes every card height changes. I tried to use direction="row" and direction="column" but it doesn't seem to work. I was wondering if there a way to change the height of the image inside depending on the size of the image while having a grid like the website above.
All I can see at the moment is this:
Here is my code for the card:
import React from 'react';
import Card from '#material-ui/core/Card';
import CardHeader from '#material-ui/core/CardHeader';
import CardMedia from '#material-ui/core/CardMedia';
import CardContent from '#material-ui/core/CardContent';
import CardActions from '#material-ui/core/CardActions';
import Avatar from '#material-ui/core/Avatar';
import IconButton from '#material-ui/core/IconButton';
// import Typography from '#material-ui/core/Typography';
import FavoriteIcon from '#material-ui/icons/Favorite';
import ShareIcon from '#material-ui/icons/Share';
import MoreVertIcon from '#material-ui/icons/MoreVert';
import { useStyles } from '../style/card.styles';
export default function Cards({ profile, sourceImage }) {
const classes = useStyles();
return (
<Card className={classes.root} style={{ height: '100%' }}>
<CardHeader
avatar={
<Avatar aria-label="recipe" src={profile} className={classes.avatar}>
</Avatar>
}
action={
<IconButton aria-label="settings">
<MoreVertIcon />
</IconButton>
}
title="Shrimp and Chorizo Paella"
subheader="September 14, 2016"
/>
<CardContent>
<CardMedia
className={classes.media}
image={sourceImage}
title="Paella dish"
/>
{/* <img src={sourceImage} style={{ maxHeight: '20rem' }} /> */}
</CardContent>
<CardActions disableSpacing>
<IconButton aria-label="add to favorites">
<FavoriteIcon />
</IconButton>
<IconButton aria-label="share">
<ShareIcon />
</IconButton>
</CardActions>
</Card>
);
}
And the layout page:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Grid from '#material-ui/core/Grid';
import Cards from './Card';
import vertical from '../images/v1.jfif';
import horizontal from '../images/h1.png';
import '../style/card.css';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
paper: {
height: 140,
width: 100,
},
control: {
padding: theme.spacing(2),
}
}));
export default function HomePage() {
const imagess = [vertical, horizontal, vertical, horizontal]
const classes = useStyles();
return (
<Grid container justify="center" className={classes.root} spacing={2}>
<Grid item xs={12}>
<Grid container alignItems="flex-start" justify="center" spacing={1}>
{imagess.map((image, index) => (
<Grid key={index} item>
<Cards profile={""} sourceImage={image} />
</Grid>
))}
</Grid>
<Grid container alignItems="flex-start" justify="center" spacing={1}>
{imagess.map((image, index) => (
<Grid key={index} item>
<Cards profile={""} sourceImage={image} />
</Grid>
))}
</Grid>
</Grid>
</Grid>
);
}
I think what you are looking for is a masonry grid. It's worth a google search.
What these packages do is calculate positions within a container on page load and resize. One example for react could be react-responsive-masonry
Example usage with react-responsive-masonry
import React from "react"
import Masonry, {ResponsiveMasonry} from "react-responsive-masonry"
// The number of columns change by resizing the window
class MyWrapper extends React.Component {
render() {
return (
<ResponsiveMasonry
columnsCountBreakPoints={{350: 1, 750: 2, 900: 3}}
>
<Masonry>
<ChildA />
<ChildB />
{/* Children */}
<ChildY />
<ChildZ />
</Masonry>
</ResponsiveMasonry>
)
}
}
// The number of columns don't change by resizing the window
class MyWrapper extends Component {
render() {
return (
<Masonry columnsCount={3}>
<ChildA />
<ChildB />
{/* Children */}
<ChildY />
<ChildZ />
</Masonry>
)
}
}
In case of the material ui you would basically replace the Grid and only render cards inside the Masonry.

How can I reuse code wrapping Material-UI's Grid while varying the number of columns?

I would like the second grid block under the title "Other Projects of Note" to be mapped through as a 3 column grid. How can I do this without creating a new component? Material-UI controls it's columns with the grid item xs={12} sm={6} and on the 3 column grid I'd need it to read as grid item xs={12} sm={6} lg={4}.
It seems like I'd be copying and pasting the <Card /> component and renaming it to achieve this. I'd like to avoid that. Demo below:
codesandbox
Here's the code for my current Card component:
import React from 'react';
import Grid from '#material-ui/core/Grid';
import Card from '#material-ui/core/Card';
import CardActionArea from '#material-ui/core/CardActionArea';
import CardActions from '#material-ui/core/CardActions';
import { makeStyles } from '#material-ui/core/styles';
import { loadCSS } from 'fg-loadcss';
import CardContent from '#material-ui/core/CardContent';
import CardMedia from '#material-ui/core/CardMedia';
import Button from '#material-ui/core/Button';
import Typography from '#material-ui/core/Typography';
import Box from '#material-ui/core/Box';
import Icon from '#material-ui/core/Icon';
import GitHubIcon from '#material-ui/icons/GitHub';
import Tooltip from '#material-ui/core/Tooltip';
import Zoom from '#material-ui/core/Zoom';
import Link from '#material-ui/core/Link';
const useStyles = makeStyles((theme) => ({
root: {
maxWidth: '100%',
flexGrow: 1,
},
cardGrid: {
paddingTop: theme.spacing(2),
},
media: {
height: 340,
},
button: {
margin: theme.spacing(1),
},
arrow: {
color: theme.palette.common.black,
},
tooltip: {
backgroundColor: theme.palette.common.black,
},
icons: {
'& > .fab': {
marginRight: theme.spacing(4),
},
margin: '1rem 0',
},
}));
function TwoCard(props) {
const classes = useStyles();
React.useEffect(() => {
const node = loadCSS(
'https://use.fontawesome.com/releases/v5.12.0/css/all.css',
document.querySelector('#font-awesome-css')
);
return () => {
node.parentNode.removeChild(node);
};
}, []);
return (
<>
<Grid item xs={12} sm={6}>
<Card>
<CardActionArea>
<CardMedia
className={classes.media}
image={props.card.image}
title='Contemplative Reptile'
/>
<CardContent className={classes.content}>
<Typography gutterBottom variant='h5' component='h2'>
{props.card.project}
</Typography>
<Typography variant='subtitle1' gutterBottom>
{props.card.framework}
</Typography>
<Typography gutterBottom variant='body2' component='p'>
{props.card.description}
</Typography>
<Box className={classes.icons}>
<Typography gutterBottom variant='subtitle2'>
TOOLS USED
</Typography>
<Tooltip
TransitionComponent={Zoom}
arrow
title='REACT'
aria-label='react'
>
<Icon className='fab fa-react fa-3x' color='primary' />
</Tooltip>
<Tooltip
TransitionComponent={Zoom}
arrow
title='HTML5'
aria-label='add'
>
<Icon className='fab fa-html5 fa-3x' color='primary' />
</Tooltip>
<Tooltip
TransitionComponent={Zoom}
arrow
title='CSS3'
aria-label='add'
>
<Icon className='fab fa-css3 fa-3x' color='primary' />
</Tooltip>
</Box>
</CardContent>
</CardActionArea>
<CardActions>
<Button variant='outlined' size='small' color='primary'>
<Link
href={props.card.projectUrl}
target='_blank'
rel='noopener noreferrer'
className={classes.links}
underline='none'
color='inherit'
>
View Project
</Link>
</Button>
<Button
variant='outlined'
size='small'
color='primary'
className={classes.button}
endIcon={<GitHubIcon />}
>
<Link
href={props.card.githubUrl}
target='_blank'
rel='noopener noreferrer'
underline='none'
color='inherit'
>
Code
</Link>
</Button>
</CardActions>
</Card>
</Grid>
</>
);
}
export default TwoCard;
and here's the code that uses that Card component:
import React from "react";
import Grid from "#material-ui/core/Grid";
import Card from "./Card.js";
import { Typography } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles((theme) => ({
headings: {
padding: "20px 0"
}
}));
function Projects(props) {
const classes = useStyles();
let cards = props.data.map((card, i) => {
return <Card card={card} key={i} />;
});
return (
<>
<Typography variant="h4" gutterBottom>
Featured Projects
</Typography>
<Grid container spacing={2}>
{cards}
</Grid>
<Typography variant="h4" className={classes.headings}>
Other Projects of note
</Typography>
<Grid container spacing={2}>
{cards}
</Grid>
</>
);
}
export default Projects;
You can pass a prop to your Card component to control whether it is two-column or three-column. For instance, you can pass a maxColumns prop and use it in the following manner:
<Grid item xs={12} sm={6} lg={maxColumns > 2 ? 4 : undefined}>
Then your Projects component can pass the prop (in my example, I'm defaulting maxColumns to 2, so it doesn't need to be specified in that case):
import React from "react";
import Grid from "#material-ui/core/Grid";
import Card from "./Card.js";
import { Typography } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles((theme) => ({
headings: {
padding: "20px 0"
}
}));
function Projects(props) {
const classes = useStyles();
let twoColumnCards = props.data.map((card, i) => {
return <Card card={card} key={i} />;
});
let threeColumnCards = props.data.map((card, i) => {
return <Card maxColumns={3} card={card} key={i} />;
});
return (
<>
<Typography variant="h4" gutterBottom>
Featured Projects
</Typography>
<Grid container spacing={2}>
{twoColumnCards}
</Grid>
<Typography variant="h4" className={classes.headings}>
Other Projects of note
</Typography>
<Grid container spacing={2}>
{threeColumnCards}
</Grid>
</>
);
}
export default Projects;

Resources