Target nested material component in JSS style definition - reactjs

I have this JSX layout currently
<div className={classes.bottomArea}>
<Box display="flex" flexDirection="column">
<Typography variant="h1" component="span">1982</Typography>
<Typography variant="h5" component="span">Bed Count</Typography>
</Box>
</div>
And in my styles I'm trying to change the color of the h5 Typography element
bottomArea: {
$h5: {
color: "red"
}
}
I think I understand why this isn't working but is there an easy way to target that h5 variant?
Here is a codesandbox to show
https://codesandbox.io/s/material-demo-wb7ts

Assuming that you want to retain <span> as your component, you can target the h5 variant by targeting the CSS class added by Typography which is MuiTypography-h5.
In the syntax shown below, the & refers to the class generated for bottomArea and then the space indicates targeting .MuiTypography-h5 as a descendant.
import React from "react";
import Typography from "#material-ui/core/Typography";
import Box from "#material-ui/core/Box";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles({
bottomArea: {
"& .MuiTypography-h5": {
color: "red"
}
}
});
export default function Types() {
const classes = useStyles();
return (
<div className={classes.bottomArea}>
<Box display="flex" flexDirection="column">
<Typography variant="h1" component="span">
1982
</Typography>
<Typography variant="h5" component="span">
Bed Count
</Typography>
</Box>
</div>
);
}
JSS Documentation: https://cssinjs.org/jss-plugin-nested/?v=v10.3.0#use--to-reference-selector-of-the-parent-rule
Related answer: How do you change a style of a child when hovering over a parent using material-ui jss styles

You are using the Typography props the wrong way. The variant props only defines the style applied to the component whereas the component props defines which tag will be used to render this component.
If you want your Typography component to be a h5:
<Typography variant="h5" component="h5">Bed Count</Typography>
And then for the styling:
bottomArea: {
'& h5': {
color: "red"
}
}
CodeSanbox: https://codesandbox.io/s/material-demo-6i1lq?file=/demo.js
Great day !

you can use withStyle to update the specific component classes
check this Typography API
const Typography = withStyles(() => ({
h5: {
color: "red",
},
}))(MuiTypography);
export default function Types() {
return (
<div>
<Box display="flex" flexDirection="column">
<Typography variant="h1" component="span">
1982
</Typography>
<Typography variant="h5" component="span">
Bed Count
</Typography>
</Box>
</div>
);
}

Related

Text not aligning properly on MUI card component

I am new to react, I've been following a course and building a demo project. I've tried but for some reason i can't align the price text on a card that has a single line of description. In fact, I want the price to appear on the bottom left of the cards. This is what my code looks like. Any suggestion would be appreciated.
import Card from '#mui/material/Card';
import CardContent from '#mui/material/CardContent';
import CardMedia from '#mui/material/CardMedia';
import Typography from '#mui/material/Typography';
const ItemCard = (props) => {
// return <div className={classes.card}>{props.children}</div>;
return (
<div>
<Card
sx={{
maxWidth: 345,
maxHeight: '100%',
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.25)',
height: '350px'
}}
>
<CardMedia component='img' height='200' image={props.img} alt='icon' />
<CardContent>
<Typography gutterBottom variant='h5' component='div'>
{props.name}
</Typography>
<Typography variant='body2' color='text.secondary'>
{props.description}
</Typography>
<Typography style={{}}>TK. {props.price}</Typography>
</CardContent>
</Card>
</div>
);
};
export default ItemCard;
Please see this image
You can add a min-height css property in your description Typography component like below (make sure the height is enough for fitting two lines. In case you have longer than two lines of description you can add the ellipsis css properties like in this solution):
<Typography variant='body2' color='text.secondary' sx={{minHeight: "30px"}}>
{props.description}
</Typography>
You can do this!
<CardActions>
<Typography style={{}}>TK. {props.price}</Typography>
</CardActions>

TypeError: Cannot read properties of undefined (reading 'up') MUI

In my Header component my custom styling are coming from style.js where I've used makeStyles from #mui/styles. But In there while setting up the [theme.breakpoints.up("sm")] I'm getting the error above. I tried wrapping the index.js with themeProvider and passed createTheme as prop. but it is giving me another error. I tried looking up the docs but couldn't figure it out.
styles.js
import { makeStyles } from "#mui/styles";
import { alpha } from "#mui/material/styles";
export default makeStyles((theme) => ({
title: {
display: "none",
[theme.breakpoints.up("sm")]: {
display: "block",
},
},
...
})
)
Header component
import React from "react";
import useStyles from "./styles";
import { AppBar, Toolbar, Typography, InputBase, Box } from "#mui/material";
import { Autocomplete } from "#react-google-maps/api";
import { SearchIcon } from "#mui/icons-material/Search";
const Header = () => {
const classes = useStyles();
return (
<AppBar position="static">
<Toolbar className={classes.toolbar}>
<Typography variant="h5" className={classes.title}>
Travel Companion
</Typography>
<Box display="flex">
<Typography variant="h6" className={classes.title}>
Explore new places
</Typography>
<Autocomplete>
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase
classes={{ root: classes.inputRoot, input: classes.inputInput }}
placeholder="Search"
/>
</div>
</Autocomplete>
</Box>
</Toolbar>
</AppBar>
);
};
export default Header;

What is wrong with my iconButton in React JS?

The console announce mistake at my IconButton open tag as unexpected token. i have installed material ui...i don't know what is the problem? can anyone help me? Thank you so much!
This is my product.js:
import React from 'react'
import {
Card,
CardMedia,
CardContent,
CardActions,
Typography,
IconButton
} from '#material-ui/core'
import {
AddShoppingCart
} from '#material-ui/icons'
import useStyles from './styles'
const Product = ({
product
}) => {
const classes = useStyles()
return (
<Card className={classes.root}>
<CardMedia className={classes.media} image='' title={product.name} />
<CardContent>
<div className={classes.cardContent}>
<Typography gutterBottom variant="h5" >
{product.name}
</Typography>
<Typography variant="h5" >
{product.price}
</Typography>
</div>
</CardContent>
<CardActions disableSpacing className={classes.cardActions}>
<IconButton aria-label="Add to Cart">
<AddShoppingCart />
</IconButton>
</CardActions>
</Card>
)
}
export default Product
This is my styles.js:
import {
makeStyles
} from '#material-ui/core/styles'
export default makeStyles(() => ({
{
root: {
maxWidth: '100%'
},
media: {
height: 0,
paddingTop: '56.25%'
},
cardActions: {
display: 'flex',
justifyContent: 'space-between'
},
}
}))
Btw i don't get where useStyles in my product.js come from when in my styles.js it's makeStyles not useStyles (i follow a tutorial on yt and he does so)
This: import useStyles from './styles' is named that because you/him wanted to, because you're exporting export default makeStyles.
export default means that you can import it with any name you want, its not a named export.
The problem maybe because here:
// You're returning an object of an object, instead of the inner { root: ... }.
({
{
root: {
maxWidth: '100%'
},
media: {
height: 0,
paddingTop: '56.25%'
},
cardActions: {
display: 'flex',
justifyContent: 'space-between'
},
}
}))
so maybe classes is not defined correctly, it would be needed the error stack to make sure where the error is, or at least a simple jsfiddle with the error would do.
There is nothing wrong with your IconButton component.
Some hints:
You can import your styles as classes right away, otherwise I doubt the class definitions will work at all.
Ensure you have installed #material-ui/icons
I took your code and did above changes:
import React from "react";
import {
Card,
CardMedia,
CardContent,
CardActions,
Typography,
IconButton
} from "#material-ui/core";
import { AddShoppingCart } from "#material-ui/icons";
import classes from "./styles";
const Product = ({ product }) => {
return (
<Card className={classes.root}>
<CardMedia className={classes.media} image="/" title={product.name} />
<CardContent>
<div className={classes.cardContent}>
<Typography gutterBottom variant="h5" component="h2">
{product.name}
</Typography>
<Typography gutterBottom variant="h5" component="h2">
{product.price}
</Typography>
</div>
</CardContent>
<CardActions disableSpacing className={classes.cardActions}>
<IconButton aria-label="Add to Cart">
<AddShoppingCart />
</IconButton>
</CardActions>
</Card>
);
};
export default Product;
See: https://codesandbox.io/s/ecstatic-sea-m9k33?file=/src/Product.js
we have used an arrow function to inline the event handler for out input field
So use
function Product({product}) {...}
instead of
const Product = ({ product }) => {}

How can I change styling of all Material UI Typography components in single react component without applying a class to every element?

I'm struggling with the way you apply styles in a React SPA with Material UI components. I have the feeling to have missed some key point in the concept.
Say I have the following Header component:
const Header = () => (
<AppBar position="fixed" >
<Toolbar>
<Link component={RouterLink} to="/">
<Typography variant="h6" noWrap>
Home
</Typography>
</Link>
<Link component={RouterLink} to="/trainings">
<Typography variant="h6" noWrap>
Trainings
</Typography>
</Link>
</Toolbar>
</AppBar>
);
How can I apply some styling to say all Typography components in the Header component. I know I can use makeStyles with the useStyles hook like this:
const useStyles = makeStyles((theme: Theme) =>
createStyles({
headerText: {
color: 'white',
},
})
);
const Header: FC = () => {
const classes = useStyles();
return (
<div>
<AppBar position="fixed">
<Toolbar>
<Link component={RouterLink} to="/">
<Typography className={classes.headerText} variant="h6" noWrap>
Home
</Typography>
</Link>
<Link component={RouterLink} to="/trainings">
<Typography className={classes.headerText} variant="h6" noWrap>
Trainings
</Typography>
</Link>
</Toolbar>
</AppBar>
</div>
);
};
export default Header;
But that would require me to apply the className prop to every element I want to style.
I also came up with the following solution that seems to work, which applies the color to all h6 elements under the root div.
const useStyles = makeStyles((theme: Theme) =>
createStyles({
headerText: {
'& h6': {
color: 'white',
},
},
})
);
const Header: FC = () => {
const classes = useStyles();
return (
<div className={classes.headerText}>
<AppBar position="fixed">
<Toolbar>
<Link component={RouterLink} to="/">
<Typography variant="h6" noWrap>
Home
</Typography>
</Link>
<Link component={RouterLink} to="/trainings">
<Typography variant="h6" noWrap>
Trainings
</Typography>
</Link>
</Toolbar>
</AppBar>
</div>
);
};
But all these solutions don't quite feel right^^
Isn't there a way to just say 'I want all Typography components in THIS Header component to have a color of white?
You can use a MuiThemeProvider to make provide a theme object and make your changes there. If you take a look at the docs
const theme = createMuiTheme({
overrides: {
// Style sheet name ⚛️
MuiButton: {
// Name of the rule
text: {
// Some CSS
color: 'white',
},
},
},
});
// ...
return (
<ThemeProvider theme={theme}>
<CssBaseline />
{children}
</ThemeProvider>
);
And for the Typography you can find the class names here
UPDATE
If you are searching for a solution to update the Typography only in the AppBar then you need to style your AppBar. You can find the classNames for your required typography in it's API (link above)
const useStyles = makeStyles({
root: {
'& .MuiTypography-root': {
color: 'black'
}
}
})
...
const classes=useStyles()
return (
<AppBar classes={{root: classes.root}}>
<Typography>Hello StackBlitz!</Typography>
</AppBar>
);
Here's a live example

How to make each Card the same size in my Material Grid

I learn React and following this tutorial but even I have the same code the result is not the same. From the tutorial I want to have a Grid like this:
Image from the Tutorial
But what I get is this:
Image from my code
import React, { Component } from 'react';
import { connect } from "react-redux";
import { withStyles } from '#material-ui/styles';
import { Grid, Paper, Typography } from "#material-ui/core";
import Card from "#material-ui/core/Card";
import CardActionArea from "#material-ui/core/CardActionArea";
import CardContent from "#material-ui/core/CardContent";
const images = require.context('../../public/images', true);
export class Posts extends Component {
constructor() {
super();
}
componentDidUpdate(prevProps) {
}
render() {
const { classes } = this.props;
return (
<div style={{ marginTop: 20, padding: 30 }}>
<Grid container spacing={40} justify="center">
{this.props.books.map(post => (
<Grid item key={post.title} Box width={1 / 4}>
<Card>
<CardActionArea>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{post.title}
</Typography>
<Typography component="p">{post.description}</Typography>
<Typography component="p">{post.author}</Typography>
<Typography component="p">{post.genre}</Typography>
<Typography component="p">{post.publish_date}</Typography>
<Typography component="p">{post.price}</Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
))}
</Grid>
</div>
);
}
}
function mapStateToProps(state) {
return {
books: state.reducer.booksList
}
}
export default connect(mapStateToProps)(withStyles(styles)(Posts));
What am I doing wrong? I think it´s the text that forces the Card to be bigger but I have not read about how to constraint text if that is possible
You can apply style to the cards
var cardStyle = {
display: 'block',
width: '30vw',
transitionDuration: '0.3s',
height: '45vw'
}
And in your CardStyle you can apply the above styling by
<Card style={cardStyle}>
<CardHeader
title="URL Avatar"
subtitle="Subtitle"
avatar="https://placeimg.com/800/450/nature"
/>
Your post.titles are long. You can use a fluid grid. Remove Box width={1 / 4} from Grid item.
<Grid item key={post.title} xs={3}>
xs={3} to scale to 1/4 of the container.
You can also set noWrap property to show an ellipsis for long titles instead of a wrapping.
<Typography noWrap ...>
{post.title}
</Typography>

Resources