styled-components doesn't work with material-ui - reactjs

my question is what is the different between this two { styled }??
import { styled } from "#mui/system";
and
import styled from "styled-components";
---------------------------
hi friends,
i am using material-ui with reactjs to create a website, then i want to add my custom style with help styled-component to the material-ui components ( Specifically, I want to change the AppBar style ) .
But I faced 2 problem.
First problem
i am try to create my custom design with styled-component library:
import styled from "styled-components";
but i must use so many ( !important ) to change the design, like this:
import styled from "styled-components";
import AppBar from "#mui/material"
const CustomNavbar = styled(AppBar)`
background-color: red !important;
position: relative !important;
color: yellow !important;
`;
2.Second Problem - ( it is work without any problem )
i searched for custom styling mui-components then i use the { styled } from mui,
import { styled } from "#mui/system";
and it is work without any problem ..
import { styled } from "#mui/system";
import AppBar from "#mui/material"
const CustomNavbar = styled(AppBar)`
background-color: red;
position: relative ;
color: yellow;
`;
so my question is
what is the different between this two { styled }??
import { styled } from "#mui/system";
and
import styled from "styled-components";
Thank you very much for giving me time and answering this question.

There is section in documentation of MUI about that, if you need to get rid of important, you need to wrap you app in
<StyledEngineProvider injectFirst>
{/* Your component tree. Now you can override MUI's styles. */}
</StyledEngineProvider>
from mui, because it will change order of importing styles.
source: https://mui.com/guides/interoperability/#css-injection-order

Related

IconButton from MUI no longer changes hover color with makeStyles?

Hi I was looking in a way to change the hover color from IconButton However the solution-sandbox that I found doesn't seem to be working anymore
This is what I have Code-Sandbox
From https://mui.com/guides/migration-v4/#style-library:
The style library used by default in v5 is emotion. While migrating from JSS to emotion, and if you are using JSS style overrides for your components (for example overrides created by makeStyles), you will need to take care of the CSS injection order. To do so, you need to have the StyledEngineProvider with the injectFirst option at the top of your component tree.
If I change your index.js to the following, the style overrides work:
import { StyledEngineProvider } from "#mui/material/styles";
import ReactDOM from "react-dom";
import App from "./App";
const rootElement = document.getElementById("root");
ReactDOM.render(
<StyledEngineProvider injectFirst>
<App />
</StyledEngineProvider>,
rootElement
);
In addition to adding <StyledEngineProvider injectFirst>, I also removed StrictMode since makeStyles doesn't support it -- styles generated by makeStyles will not get maintained in the DOM reliably in strict mode.
Since you're using v5, the better option would be to avoid makeStyles (which is deprecated in v5) entirely and use styled instead. Then you don't need the index.js changes and can keep strict mode.
import React from "react";
import { styled } from "#mui/material/styles";
import IconButton from "#mui/material/IconButton";
const StyledIconButton = styled(IconButton)(`
&:hover, &.Mui-focusVisible {
background-color: yellow;
}
`);
You should add !important to your style then it should work
const useStyles = makeStyles((theme) => ({
customHoverFocus: {
"&:hover, &.MuiIconButton": { background: "yellow !important" }
}
}));

How to apply global styling to a react component library?

I am developing a React Component Library and I am struggling to apply some global styles (like resetting things) to the global level to be applied to all my components.
For instance, my app JS is something like this.
import './styles.module.css';
import Button from './Components/Button';
import Navbar from './Components/Navbar';
import Input from './Components/Input';
export {
Button,
Navbar,
Input,
}
and a generic global css file would be something like this:
:root {
padding: 0;
margin: 0;
}
I thought of using the approach from Styled Components as well, but as I don't have anything wrapping my components (it's a library), I don't know exactly where/how to use it.
Any hints ?
This wouldn't be the most elegant solution, but you could create a mixin (with default styles) and import it within each component.
In styled-component you could do it like this:
Define mixin in a file and export it
import { css } from 'styled-components';
export const defaultStyles = css`
margin: 0;
padding: 0;
// other default styles go here...
`
and then use it in each component like:
import styled from 'styled-component'
import {defaultStyle} from './path/to/file/from/where/you/export/defaultStyle'
const Button = styled.button`
${defaultStyles}
border: none;
// other commponent specific styles go here...
`

Using SCSS In Material UI React directly

I have some issue using scss directly in material ui, because not all styles are applied. Tried to use makeStyle, but because I use class component, it gives warning about invalid hook call.
The style :
.table-header {
background-color: #005CAA; //only this style works
color: white;
font-weight: bold;
text-align: center;
}
I call in in TableCell component from Material UI
<TableCell className="table-header">Invoice Number</TableCell>
For the scss file, I import it in parent component App.tsx, or I need to import the file directly in the Table component? Thx
I follow the makeStyles approach as it's recommended way of overriding the material-ui styles, else you'd have to use !important in your css/scss files to override the material-ui styles.
https://mui.com/styles/basics/
// component file
import React from 'react';
import { TextLineStyles } from './styles';
export default function TextLine({ text }) {
const classes = TextLineStyles()
return <div className={classes.root}>
<div data-title="line" >
<div data-title="text">
{text}
</div>
</div>
</div>
}
// style.js
import { makeStyles } from "#material-ui/core/styles";
export const TextLineStyles = makeStyles(theme => ({
root: {
'& [data-title="line"]': {
borderTop: `1px solid lightgray`,
'& [data-title="text"]': {
color: 'red' // scss like nesting
}
}
}
}));
If you want to use CSS/SCSS class in MUI component, you should import the file directly in the Table component. But, it's not good to use SCSS with MUI component, you should use makeStyles or withStyles to style the MUI component.
I am not sure if it is the best practice, in fact thats why I ended up in this post.
Here it explain how to use scss with material-ui: https://www.markmakesstuff.com/posts/mui-css-modules
"Just install node-sass"
"if you're working with an app you initialized with a script like create-react-app, you are in luck. No webpack edits necessary. Just give your module a name that ends with ".module.scss""
OTHERWISE
2') You need to "make some minor edits to your webpack config"
"You can then import your module with a name then use that to refer to your classes when writing your fancy JSX"

How to overwrite styles with classes and css modules?

Focused, checked classes seems to not work properly.
I need to always use !important or use jss styles provided by material-ui.
For example:
https://codesandbox.io/s/css-modules-nvy8s?file=/src/CssModulesButton.js
CssModulesButton.module.css
.checkboxtest {
color: blue;
}
.checkboxtestworking {
color: blue !important;
}
CssModulesButton.js
import React from "react";
// webpack, parcel or else will inject the CSS into the page
import styles from "./CssModulesButton.module.css";
import Checkbox from "#material-ui/core/Checkbox/Checkbox";
export default function CssModulesButton() {
return (
<div>
<Checkbox classes={{ checked: styles.checkboxtest }}>testasd</Checkbox>
<Checkbox classes={{ checked: styles.checkboxtestworking }}>
testasd
</Checkbox>
</div>
);
}
index.js
import React from "react";
import { render } from "react-dom";
import { StylesProvider } from "#material-ui/core/styles";
import CssModulesButton from "./CssModulesButton";
import CssBaseline from "#material-ui/core/CssBaseline";
const App = () => <CssModulesButton />;
render(<App />, document.querySelector("#root"));
I cant overwrite Checkbox color in any other way than using !important.
The problem persists when using classes={{focused:styles.focused}} and many others.
Is there a way to simply overwrite components with classes without !important? Sometimes even !important doesnt work
inb4 im using injectFirst
You mentioned injectFirst in your question, though your sandbox example wasn't using it. You should use it since this will make sure that the CSS from your CSS modules is inserted after the Material-UI CSS in the <head> element. When specificity is the same, the styles that occur later will win over earlier styles.
The default styles for the checkbox colors are as follows:
colorSecondary: {
'&$checked': {
color: theme.palette.secondary.main,
'&:hover': {
backgroundColor: fade(theme.palette.secondary.main, theme.palette.action.hoverOpacity),
// Reset on touch devices, it doesn't add specificity
'#media (hover: none)': {
backgroundColor: 'transparent',
},
},
},
'&$disabled': {
color: theme.palette.action.disabled,
},
},
Below is the corresponding CSS generated by JSS:
.MuiCheckbox-colorSecondary.Mui-checked {
color: #f50057;
}
.MuiCheckbox-colorSecondary.Mui-disabled {
color: rgba(0, 0, 0, 0.26);
}
.MuiCheckbox-colorSecondary.Mui-checked:hover {
background-color: rgba(245, 0, 87, 0.04);
}
#media (hover: none) {
.MuiCheckbox-colorSecondary.Mui-checked:hover {
background-color: transparent;
}
}
The important aspect to notice is that the checked style is done via two classes. In order to override these styles you need that same degree of specificity or greater.
Below is a full working example overriding the checked color of the checkbox:
index.js (important part here is <StylesProvider injectFirst>)
import React from "react";
import { render } from "react-dom";
import { StylesProvider } from "#material-ui/core/styles";
import CssModulesButton from "./CssModulesButton";
const App = () => (
<StylesProvider injectFirst>
<CssModulesButton />
</StylesProvider>
);
render(<App />, document.querySelector("#root"));
CssModulesButton.module.css
Uses two classes in the style declaration -- the checkboxtest CSS module class and Mui-checked (the global class which Material-UI adds for the checked state)
.checkboxtest:global(.Mui-checked) {
color: blue;
}
CssModulesButton.js
import React from "react";
import styles from "./CssModulesButton.module.css";
import Checkbox from "#material-ui/core/Checkbox";
export default function CssModulesButton() {
return (
<div>
<Checkbox className={styles.checkboxtest} />
</div>
);
}
Follow-up question from the comments:
Could you explain why can't I use classes? Shouldn't classes={{checked:styles.AnyClass}} overwrite the styles successfully? I understand why it doesn't, but what is the purpose of classes then?
You can use the classes prop, but there isn't any compelling reason to do so in this case. The following will also work, so long as the declaration for the styles is the same (using two CSS classes) so that you have the appropriate degree of specificity:
<Checkbox classes={{ checked: styles.checkboxtest }} />
As far as the second part of your question ("what is the purpose of classes then?"), there are two main reasons to use the classes prop. Some of the CSS classes for the classes prop get applied to different elements within the component, and some only get applied when the component is in a particular state, or when certain props have been used on the component. In this case, you are trying to target these styles for a particular state of the component. In v3 of Material-UI, you would have needed to use the classes prop to provide a class name that would only be applied for the checked state, but in v4 Material-UI switched to using global class names for these states (more details here: https://material-ui.com/customization/components/#pseudo-classes) such as Mui-checked. This makes it easier to target these states via a single generated class (a big driver of this change was to make it easier to customize Material-UI components using styled-components).

Overriding react components styles with styled component

I tried to override style of component created by standard way of styled-components(styled.) and both the ways(styled() and style.extends) worked for me.
But when I am trying to override style of simple react component with styled() approach, its rendering the component but not overriding it's style.
Below is snippet of code
import React, { Component } from "react";
import styled from "styled-components";
export default class MyLabel extends Component {
render() {
return <label>{this.props.children}</label>;
}
}
const StyledMyLabel = styled(MyLabel)`
color: green;
`;
And for display purpose I am using following syntax
<StyledMyLabel>My Styled Label</StyledMyLabel>
Please refer the link on codesandbox which might be useful
You have to pass className to desirable styling element manually to make it works.
import React, { Component } from "react";
import styled from "styled-components";
export default class MyLabel extends Component {
render() {
return <label className={this.props.className}>{this.props.children}</label>;
}
}
const StyledMyLabel = styled(MyLabel)`
color: green;
`;
NOTE:
Consider carefully whether to wrap your own components in a styled component, when it isn't necessary. You will disable the automatic whitelisting of props, and reverse the recommended order of styled components and structural components.
See more info here.
<label style={{color: "green"}}>{this.props.children}</label>
or
const style = {color : "green"};
<label style={style}>{this.props.children}</label>

Resources