How to overwrite styles with classes and css modules? - reactjs

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).

Related

Change the link colors in Material UI Sidebar (Drawer) in a Reactjs app

I tried using different properties in the sidebar style to override the link color but nothing is working.
Default style/color of Sidebar drawer (before overriding the style)
MySidebar.js
// MySidebar.js
import { Sidebar } from 'react-admin';
import { makeStyles } from '#material-ui/core/styles';
import React from 'react';
const useSidebarStyles = makeStyles({
drawerPaper: {
backgroundColor: '#0c2d48',
color: '#fff',
},
});
const MySidebar = props => {
const classes = useSidebarStyles();
return (
<Sidebar classes={classes} {...props} />
);
};
export default MySidebar;
MyLayout.js
// MyLayout.js
import React from 'react';
import { Layout } from 'react-admin';
import MySidebar from './MySidebar';
const MyLayout = props => (
<Layout
{...props}
sidebar={MySidebar}
/>
);
export default MyLayout;
Result (after overriding the default style in MySidebar.js)
As you can see, I'm able to change bg color of the sidebar but not the link colors.
Please help. It's driving me crazy!
You can create your own theme as described here:
https://marmelab.com/react-admin/Theming.html#writing-a-custom-theme
and in your theme redefine the colors of all MenuItemLink components:
export const lightTheme = {
...
overrides: {
RaMenuItemLink: {
root: {
color: "#c51162",
},
active: {
color: "#ff4081",
},
},
},
}
I can see that you are using React-Admin for the sidebar and not the Material UI sidebar directly. So possibly the React-Admin template modified the props of original material Ui and you should take a look inside the react admin sidebar and modify it directly there to get the results. If you apply material UI customization on this one, it might be the reason its not working.
Alternative is to try Material UI Themeing with ThemeProvider and apply the theme, which can overwrite the current styling.
Try changing link colors.
drawerPaper: {
backgroundColor: '#0c2d48',
color: '#fff',
},
link: {
color: '#fff',
},
Update: Instead of link you can give it the css class name, by looking at inspect element on the ouput sidebar.

Where does FilledInput inherit backgroundColor property in Mui?

I was working on Filled Inputs in form of TextFields as well as FilledInput. I need a solution to make the background color of all the FilledInputs, currently, I am using makeStyle and adding class names to each component, which seems redundant.
Can someone give a better workaround, like changing some property in the theme?
From the FilledInput API docs we can learn that:
The MuiFilledInput name can be used for providing default props or
style overrides at the theme level.
And from this this guide in overriding MUI CSS globally we can learn to use overrides key of the theme to potentially change every single style injected by Material-UI into the DOM
Sample Code:
import React from "react";
import { createMuiTheme, ThemeProvider } from "#material-ui/core/styles";
import FilledInput from "#material-ui/core/FilledInput";
const theme = createMuiTheme({
overrides: {
// Style sheet name
MuiFilledInput: {
// Name of the rule
root: {
backgroundColor: "orange"
}
}
}
});
function OverridesCss() {
return (
<ThemeProvider theme={theme}>
<FilledInput placeholder="sample placeholder" />
</ThemeProvider>
);
}
export default OverridesCss;

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"

What does the CssBaseline class do?

I've been wondering what the CssBaseline class in the Material-UI React library does, but I can't seem to find an answer anywhere, and the page I linked doesn't do much explaining about what the class does. Does anyone here know what this component is supposed to do?
CssBaseline is sort of css reset added to the <head /> of your document. If you are familiar with similar approaches like normalize.css which adds some default visual styling to default elements, resets paddings and etc ...
Material-UI provides some reset styles as you can observe here CssBasline.js mainly box-sizing and body font color and background color
'#global': {
html: {
WebkitFontSmoothing: 'antialiased', // Antialiasing.
MozOsxFontSmoothing: 'grayscale', // Antialiasing.
// Change from `box-sizing: content-box` so that `width`
// is not affected by `padding` or `border`.
boxSizing: 'border-box',
},
'*, *::before, *::after': {
boxSizing: 'inherit',
},
'strong, b': {
fontWeight: 'bolder',
},
body: {
margin: 0, // Remove the margin in all browsers.
color: theme.palette.text.primary,
...theme.typography.body2,
backgroundColor: theme.palette.background.default,
'#media print': {
// Save printer ink.
backgroundColor: theme.palette.common.white,
},
},
The docs say that its a collection of HTML element and attribute style-normalizations. It's based on normalize.js, which is a modern cross-browser CSS reset for your HTML elements that preserves some of the defaults.
Basically, it resets your CSS to a consistent baseline. That way, you can restyle your HTML doc so that you know you can expect all of the elements to look the same across all browsers.
What normalize.js does, from the readme linked above:
Preserves useful defaults, unlike many CSS resets.
Normalizes styles for a wide range of elements. Corrects bugs and common browser
inconsistencies.
Improves usability with subtle modifications.
Explains what code does using detailed comments.
import { createMuiTheme } from "#material-ui/core/styles";
const theme = createMuiTheme({
overrides: {
MuiCssBaseline: {
"#global": {
"*, *::before, *::after": {
boxSizing: "content-box",
},
body: {
backgroundColor: "#fff",
},
},
},
},
});
export default theme;
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import { BrowserRouter } from "react-router-dom";
import { MuiThemeProvider } from "#material-ui/core/styles";
import theme from "./Theme/Theme";
ReactDOM.render(
<MuiThemeProvider theme={theme}>
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
</MuiThemeProvider>,
document.getElementById("root")
);
serviceWorker.unregister();
Basically, The MUI provides MuiCssBaseline that overrides some of our CSS styles. But MUI
provides the flexibility to override its default style. Here is what I have implemented
1: Create a theme.js and import createMuiTheme. Then override the styles of MuiBaseline based on your requirements and export the theme.js.
2.If you want the overridden style all over your application then import theme.js, MuiThemeProvider from material-ui/core/styles into your index.js, MuiThemeProvider takes the theme as an argument and then applies the style to its children components.
Related to - but I can't seem to find an answer anywhere.
You can find code for CssBaseLine in the repository for the Material-UI library on Github by following link.
By putting at top of your component is used for providing a lot of default styling for your material UI applications so that you don't have to worry about basic styles of your component

How can I setup SCSS files (ViewEncapsulated way) in 'react app 2' like Angular component specific SCSS?

I installed 'react app 2' as well as node-sass. It's working fine with SCSS. But I just want to know how can I create component specific SCSS like Angular (that will never be a conflict with other components SCSS)
Angular automatically add an attribute for ViewEncapsulation see below example
In angular, there is an option for
encapsulation: ViewEncapsulation.None (Use to disable CSS Encapsulation for this component)
enter link description here
I know the question is old, but it has no answer, thus I want to share this article. Alsomst does the trick, with the exception that it seems to does not have support for something like ::ng-deep
React doesn't have native component styles like Angular does because it aims to keep away from any functionality that could easily be handled by third-party packages. So you have two pretty simple options:
Use styled-components to create component-specific styles. This is a pretty straightforward package that allows you to define styles for each element within a component and you can even pass variables into the styles. It generates internal CSS (kept in <style> tags in the document head) which will take precedence over external styles by default. Example:
// MainComponent.jsx
import React from 'react';
import styled from 'styled-components';
const Title = styled.h1`
color: red
`
const MainComponent = (props) => <Title>Hello World</Title>
In each of your components, add a class or ID to the root element so that you can simply add that selector to the beginning of your SCSS to only style that specific component. Example:
// MainComponent.jsx
import React from 'react';
const MainComponent = (props) => (
<div className="main-component">
<h1>Hello World</h1>
</div>
)
// MainComponent.scss
.main-component {
h1 {
color: red;
}
}
Now only h1 elements in your MainComponent will be red.
//JS
import React from "react";
import "./yourComponentName.scss";
export default props => {
const { className, children, ...restOperator } = props;
return (
<a className={`yourComponentName ${className}` } {...restOperator}>
{children}
</a>
);
}
//yourComponentName.scss
.yourComponentName{
position:relative;
background:red;
/* your property and value use nesting*/
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}

Resources