Using styled-components to style my own React components - css

I am trying to use styled-components to style my own child components.
As an example, I have created a custom card component, called myCard, as follows:
import React from "react";
import Card, { CardActions, CardContent } from "material-ui/Card";
import Button from "material-ui/Button";
import Typography from "material-ui/Typography";
const myCard = props => {
return (
<Card>
<CardContent>
<Typography>{props.cardName}</Typography>
</CardContent>
<CardActions>
<Button size="small">SELECT</Button>
</CardActions>
</Card>
);
};
export default myCard;
Now, in the parent component, I want to reuse this myCard component but with the possibility of giving any one of them a custom style, such as a border (when I eventually refactor the code to onClick):
import React, { Component } from "react";
import Grid from "material-ui/Grid";
import styled from "styled-components";
import myCard from "./myCard";
const StyledCard = styled(myCard)`
/* border-style: ${props => (props.border ? "solid" : "none")}; */
border-style: solid !important;
border-width: 5px;
width: 180px;
`;
class cardSelect extends Component {
render() {
return (
<div>
<Grid container spacing={24}>
<Grid item xs={12}>
<Grid container justify="center">
<Grid item>
<StyledCard
cardName="Bronze"
/>
</Grid>
<Grid item>
<StyledCard
cardName="Silver"
/>
</Grid>
<Grid item>
<StyledCard
cardName="Gold"
/>
</Grid>
</Grid>
</Grid>
</Grid>
</div>
);
}
}
export default cardSelect;
I admit, I find the styled-components documentation rather poor. And there is only one reference to this kind of situation, which suggests to pass the className prop to the component. However I am not truly understanding this concept.

So you really need to pass className prop to the Card component. The styled-components generates classes for you, to apply styles for not-styled-components just needs to pass className prop to the component...
const myCard = props => {
return (
<Card className={props.className}>
<CardContent>
<Typography>{props.cardName}</Typography>
</CardContent>
<CardActions>
<Button size="small">SELECT</Button>
</CardActions>
</Card>
);
};

Pass props with notations to your {...props} Card component.
import React from "react";
import Card, { CardActions, CardContent } from "material-ui/Card";
import Button from "material-ui/Button";
import Typography from "material-ui/Typography";
const myCard = props => {
return (
/**Here, pass the props with spread notation */
<Card {...props}>
<CardContent>
<Typography>{props.cardName}</Typography>
</CardContent>
<CardActions>
<Button size="small">SELECT</Button>
</CardActions>
</Card>
);
};
export default myCard;
So actually, what does this spread props do when you pass any prop to the component it will become part of the component.

I found the answer through trials and errors. Could not find this solution (at least holistic) anywhere, so for posterity and the benefit of others, this is how I solved it.
The solution is simply to pass the className prop to the myCard component as follows:
const myCard = props => {
const { className } = props;
return (
<Card className={className}>
...
So, in general, one has to pass the className prop on to the custom component that you want to render.

Related

Material-UI makeStyles cannot read property 'down' of undefined

I am working on a personal website using Material-UI and to make it responsive I wanted to hide an image on smaller screens but when I try to use [theme.breakpoints.down('md')], it keeps giving me the error:
TypeError: Cannot read property 'down' of undefined
I am a beginner and just can't figure out why I am getting this error. I referred to the documentation and others questions similar to this but I was not able to find any solution.
Here is my Component:
import React from 'react'
import { Grid ,Button,Box} from '#material-ui/core';
import { makeStyles } from "#material-ui/styles";
import './header.css'
import guy from '../../assets/img/peep_guy.svg'
const useStyles =makeStyles(theme=>({
root:{
marginLeft:"55px",
marginRight:"20px"
},
try_btn:{
background:"black",
textTransform:"none",
margin:"25px",
fontSize:"clamp(10px,2vw,20px)",
background:"#5338f8",
"&:hover":{
boxShadow:" 0 15px 30px -15px rgb(0 0 0 / 20%)",
background:"#5338f8",
},
},
boy_img:{
paddingTop:"12px",
[theme.breakpoints.down('md')]: {
display:"none"
},
}
}))
function Header() {
const {try_btn,boy_img,root} =useStyles();
return (
<div>
<Box m={5}>
<Box ml={4} />
<Grid container spacing={0} className={root}>
<Grid item lg={8} md={9} align="right">
<h1 className="heading">Don't spend $15,000 on a coding bootcamp</h1>
<h2 className="sub_head">Our career path helps motivated students become hireable frontend developers for 1% of the cost</h2>
<Button className={try_btn} color="secondary" variant="contained">Try it out now</Button>
</Grid>
<Grid item lg={3} md={2} xs={0} sm={0}>
<Box pt={3} />
<img className={boy_img} style={{transform:"scaleX(-1)"}} src={guy} alt=""/>
</Grid>
</Grid>
</Box>
</div>
)
}
export default Header
Replace
import { makeStyles } from "#material-ui/styles";
with
import { makeStyles } from "#material-ui/core/styles";
makeStyles from "#material-ui/core/styles" is a wrapper hook of the other one. This wrapper add a default theme if you don't provide one in ThemeProvider. Source.

How to style Material UI's Tab component label?

I'm looking for a way to customize the color of the text inside the Tab component but at the same time retaining the ability for it to be colored over when selected as an active Tab.
Example code:
<Tabs centered onChange={handleChange} value={value} textColor={'secondary'} indicatorColor={'secondary'}>
<Tab label={'Hello There'} style={{color: '#fff'}}/>
<Tab label={'Hello There'} style={{color: '#fff'}}/>
<Tab label={'Hello There'} style={{color: '#fff'}}/>
</Tabs>
The above code will result in the change of the text color BUT when the Tab becomes active, it won't be overridden.
If it helps, I'm also using styled-components for ease of use.
You can use the makeStyles export of material-ui to create your custom class for the label
import { makeStyles } from "#material-ui/core";
const useStyles = makeStyles({
customLabelColor: {
color: "#fff"
}
});
export default function App() {
const classes = useStyles();
return (
...
<Tab
label={"Hello There"}
classes={{
textColorSecondary: classes.customLabelColor
}}
/>
...
);
}
CodeSandBox: https://codesandbox.io/s/quirky-kowalevski-xzf7g?file=/src/App.js
Refer here for other methods on how to override the CSS for Tab.
On the same reference I linked, have a look at the textColorSecondary rule name. This is specific to your question since you are using textColor="secondary" on your parent component Tabs

Materialui - where to load CSS classes from?

This might have a quick answer. I am starting to learn Material UI and want try its grid examples, but coding below mentions that compilation rejects as NOTFOUND .. Could not locate a CSS file to load to try these examples.. Without the className parameter, i do not see any outline of the GRID, so may be these css 'classes.root' hold the formatting options. Appreciate your kind help,
function App() {
return (
<div className={classes.root}> ????
<Grid container spacing={3}>
<Grid item xs={12}>
You need to use makeStyles
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles({
root: {
backgroundColor: 'red',
color: props => props.color,
},
});
function App(props) {
const classes = useStyles(props);
return (
<div className={classes.root}>
// ...
</div>
);
}

Material UI - MakeStyles Overridden

Good day, im attempting to add custom CSS to a material UI App Bar but all the styles i apply using the makeStyles function is overridden by the default Material UI styling. The only fix is to apply !important to my styling but I dont see this as a viable workaround. Following the docs it states to use the StylesProvider component to configure the CSS injection order but this also hasnt proven any results. Please any help will be greatly appreciated here is an example of what ive attempted to do.
Index.js
import React from 'react';
import { hydrate, render } from "react-dom";
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import 'bootstrap/dist/css/bootstrap.css';
import 'typeface-roboto';
import { StylesProvider } from '#material-ui/core/styles';
const rootElement = document.getElementById("root");
if (rootElement.hasChildNodes()) {
hydrate(<StylesProvider injectFirst><App /></StylesProvider>, rootElement);
} else {
render(<StylesProvider injectFirst><App /></StylesProvider>, rootElement);
}
serviceWorker.unregister();
Component that uses MakeStyles
const navBarStyles = makeStyles((theme) => ({
link: {
margin: theme.spacing(1, 1.5)
}
}));
export default function NavbarComponent() {
const classes = navBarStyles();
return (
<AppBar position="static" elevation={0}>
<Toolbar className="flex-wrap">
<Typography variant="h6" color="inherit" noWrap className="flex-grow-1">
test
</Typography>
<nav>
<Link variant="button" color="textPrimary" href="#" className={classes.link}>
Features
</Link>
</nav>
</ToolBar>
</AppBar>
)}
Note im using React-Snap with this project so im not sure if that is the reason it is breaking, https://www.npmjs.com/package/react-snap
You can override the MUI styles using theme provider
check theme provider
Or can use classes property in Mui Component. classes
Use sx={{}} property directly in the navbar.
Something like this
<AppBar position='static' sx={{ borderRadius: '9px', color="inherit" }}>
//Other components
</AppBar>

React hover style not working when used with Radium and Material-UI

I am using Radium library for inline styling in react . Using it works fine for other components but i am having issues with Material-UI components. When i hover my mouse over the Paper , it doesn't change the color to green . What's wrong here ? How do I fix this ?
import React, { Component, Fragment } from 'react';
import { Grid, GridList, Paper, ListItem, List, ListItemIcon, ListItemText } from '#material-ui/core';
import { connect } from 'react-redux';
import Radium from 'radium';
class AchievementsHome extends Component {
render() {
return <>
<Grid container alignItems="center" direction="column">
<h1>Achievements</h1>
<Paper
style={{backgroundColor:'red' , ':hover':{backgroundColor:'green' }}
>
<h1>Hi</h1>
</Paper>
</Grid>
</>
}
}
const mapStateToProps = (state) => {
return {
achievements: state.achievements
}
}
export default connect(mapStateToProps)(Radium(AchievementsHome));
With Material UI external styles ( so styles not directly from the Material UI library ) hardly ever work, to change the color on hover you will have to set a theme as explained in the Themes section of the docs
First grab the import withStyles and define a theme.
import { withStyles } from "#material-ui/core/styles";
const customStyles = theme => ({
root: {
backgroundColor: "red",
"&:hover": {
backgroundColor: "green"
}
}
});
Than define a new component that is wrapped with withStyles:
const CustomPaper = withStyles(customStyles)(Paper);
In your render use the component you defined:
<CustomPaper
/>
Hope this helps.
Material UI provides its own way of styling using CSS in JS (JSS). It provides a withStyles higher order component and a withTheme and lets you style at a global theme level. You can also pass class names for some components for custom styling.
You do not need to use Radium to style Material UI components.
Also your CSS selector for hovering needs to include the parent CSS selector:
const paperStyle = {
backgroundColor: 'red',
'&:hover': {
backgroundColor: 'green'
}
}
return (
<Paper styles={paperStyle}>
<Typography variant="h1">Hi</Typography>
</Paper>
);

Resources