Material-UI: Overriding style classes - javascript

I was trying to follow the MUI guide on overriding MUI styles, but using styled-components instead of JSS. In particular, I could not get the first two approaches to work:
Using className
Using classes
I have made sure the injection order in head is correct, so that is not the issue. My problem is that the classes I need are not added to the DOM.
Also note: I managed to get normal styled-components to work well with MUI. I.e. the following works fine:
import React from 'react';
import Button from '#material-ui/core/Button';
import Typography from '#material-ui/core/Typography';
import styled from 'styled-components';
import { darken, fade } from '#material-ui/core/styles/colorManipulator';
const StyledButton = styled(Button)`
color: ${props => props.theme.palette.primary.contrastText };
background: linear-gradient(45deg, #fe6b8b 30%, #ff8e53 90%);
border-radius: ${props => props.theme.shape.borderRadius}px;
height: 48px;
padding: 0 30px;
box-shadow: 0 3px 5px 2px rgba(255, 105, 135, 0.3);
&:hover {
background: ${props => {
return `linear-gradient(45deg, ${darken(`#fe6b8b`, 0.2)} 30%, ${darken(`#ff8e53`, 0.2)} 90%)`;
}};
};
font-size: 1.2rem;
${props => props.theme.breakpoints.up('md')} {
font-size: 1rem;
}
`;
// In render:
<StyledButton>Hello World</StyledButton>
The following however, does not work:
styled(Typography)`
&.my-class {
margin-bottom: 5rem;
}
`;
// In render:
<Typography className="my-class" component="h2" variant="h2">
Dev Tools does show that my-class is indeed added, but, the class does not get added to the DOM. I followed this guide (Third Method).
Any idea why?
PS: I do not want to turn Typography into a StyledTypography component. I know that works (see first example above). Instead, I want to follow the override guide in the MUI docs.
Edit
Relevant installed packages:
"#material-ui/core": "^3.9.3"
"styled-components": "^4.2.0",
Edit 2:
I got it to work if I import an external style sheet:
// style.css
.my-class2 {
margin-bottom: 3rem;
}
// index.js
import React from 'react';
import Typography from '#material-ui/core/Typography';
import './style.css';
const IndexPage = () => (
<>
<Typography className="my-class2" component="h2" variant="h2">
Testing h2 (MUI)
</Typography>
</>
);
<Typography className="my-class2" component="h2" variant="h2">
Testing h2 (MUI)
</Typography>
However, I would like to keep it all inside the component.
Thus, my problem boils down to:
How can I add locally scoped styles to the DOM from within a component, without for instance creating a new component tag / variable with styled-components?

Related

How can I customize the checked state of a checkbox when using svgr in React?

I'm working on a React project and I'm using styled-component and typescript.
I'm customizing the checkbox like this:
Source
import React, { ReactElement } from 'react';
import styled from 'styled-components';
import IconChecked from '#assets/Icons/ico_checked.svg';
interface Props {
id: string;
}
const StyledCheckBox = styled.input`
box-sizing: border-box;
width: 20px;
height: 20px;
background: #ffffff;
border: 1px solid #d4dae4;
border-radius: 4px;
appearance: none;
&:checked {
background-image: url(${IconChecked});
background-repeat: no-repeat;
background-color: #ffffff;
background-position: 50%;
}
`;
const CheckBox = ({ id }: Props): ReactElement => (
<StyledCheckBox type="checkbox" id={id} />
);
export default CheckBox;
Question
To use the svg icon without the <img> tag, I installed the svgr package and set it as an svg type loader through webpack.
The problem is that svgr has the logic to convert svg to component, so I can't set the checked icon in the following way.
&:checked {
background-image: url(${IconChecked});
...
}
As a result, the check icon(IconChecked) does not appear when I click the checkbox after using svgr. How can I solve this?
You can move your ico_checked.svg file to public folder and use the svg directly from the url like this:
&:checked {
background-image: url("/ico_checked.svg");
...
}
You can take a look at this sandbox for a live working example of this approach.

Two Components Connected to Each-other

Two of my React components are connected together. You might be thinking, if they are both separate components then they shouldn't be connected, right. WRONG.
What I want to do is this. I want to create a footer but the footer is apparently linked to another component. I think this is a react bug but I have decided not to go there in case it's just my fault. I want to change the width of the footer to be max width with the screen but it doesn't work, it changes both of the components width.
.footer {
width: 100%;
}
.footer {
background-color: gray;
border: 1px solid gray;
border-radius: 1px;
height: 100px;
width: 10000px; /*Or 100%*/
}
.otherComponent {
/*For some reason it copies the same attributes as the css one above (there in different files by the way*/
width: 10000px; /*Or 100%*/ /*The one that got copied by react.*/
background-color: gray;
border: 1px solid gray;
border-radius: 1px;
height: 100px;
}
<div class="otherComponent">
</div>
<br />
<p>This is to demonstrate the bug/error that is happening with my program. And what it looks like</p>
<div class="footer">
</div>
Edit:
I am editing this question since I have received comments saying that this question is not understandable, which I understand. The problem is that I want one of the components (which is a code-box for a documentation website that I am working on) to be somehow separated from another component (which is the footer). Every time I apply a style to the footer component the code-box component is having the same styles.
Information
Both of the different styles for the components are in separate folders. They are separated away from each-other using "<br />" tags. The components are placed like this in the App.js file.
{/* Middle of the page */}
<HomeInfo />
{/* Bottom of the page */}
<Footer />
If this edit still doesn't make sense commenting on the post would help.
As there is little to go on here I'll describe one case where this could occur.
Given the following two components and root app.
Component A:
CSS:
.root {
width: 100%;
}
.component-a-heading {
color: blue;
}
Component:
import React from 'react';
import './component-a.css';
const ComponentA = () => {
return (
<div className="root">
<h1 className="component-a-heading">
I am component A
</h1>
</div>
)
}
export default ComponentB;
Component B:
CSS:
.root {
width: 50%;
}
.component-b-heading {
color: red;
}
Component:
import React from 'react';
import './component-b.css';
const ComponentB = () => {
return (
<div className="root">
<h1 className="component-b-heading">
I am component B
</h1>
</div>
)
}
export default ComponentA;
App:
import React from 'react';
import ComponentA from './ComponentA';
import ComponentB from './ComponentB';
const App = () => {
return (
<div>
<ComponentA />
<ComponentB />
</div>
);
}
export default App;
The assumed intended result is that:
ComponentA would be 100% width,
ComponentA heading would be blue,
ComponentB would be 50% width,
ComponentB heading would be red.
The reality is that:
ComponentA would be 50% width,
ComponentA heading would be blue,
ComponentB would be 50% width,
ComponentB heading would be red.
This is caused by the fact that even though the CSS unique to each component is imported per component the resulting CSS is global and effects all components that might use the class names defined within (in the example above .root).
Depending on your bundling process you might end up with a single CSS file that
looks something like this:
.root {
width: 100%;
}
.component-a-heading {
color: blue;
}
.root {
width: 50%;
}
.component-b-heading {
color: red;
}
Or you might end up with the styles inserted into the head of your HTML like this:
<style type="text/css">
.root {
width: 100%;
}
.component-a-heading {
color: blue;
}
</style>
<style>
.root {
width: 50%;
}
.component-b-heading {
color: red;
}
</style>
This is a common mistake for people who come from Angular, where imported CSS is scoped to each component, to React.
One way to get around this is to look at the possibility of using CSS Modules which will allow you to locally scope each imported CSS file (this just makes the CSS class names unique in your resulting bundle).
Another option would be to implement a naming policy to ensure that the class names remain unique between components.

Next JS styled components dark mode themeing

This probably has answer, but I was unable to find it
I am using styled components with next js and use-dark-mode hook to trigger theme change/detect
global styles switch before loading
import { createGlobalStyle } from "styled-components";
export const GlobalStyles = createGlobalStyle`
body {
background: ${props => props.theme.background};
color: ${props => props.theme.color};
font-family: Roboto, sans-serif;
margin: 0;
padding: 0;
}
`
but having simple styled component like this one
const BackgroundTopAppBar = styled.header`
background-color: ${props => props.theme.appBarHeaderBackground};
`;
doesnt change upon page loading and remains light theme colored
also inside _document.js is implemented next-js team example of how to use styled components for SSR and it works well, but for styled components that are not global dark mode is not activated after page is refreshed
thank you
For anybody looking for a solution, use GlobalStyles and in there modify current color of element because GlobalStyles will apply it before loading
export const GlobalStyles = createGlobalStyle`
body {
background: ${props => props.theme.background};
color: ${props => props.theme.color};
font-family: Roboto, sans-serif;
margin: 0;
padding: 0;
}
${BackgroundTopAppBar} {
background-color: ${props => props.theme.appBarHeaderBackground};
}
`

Use className for Material-UI component

I want tp use css to Material-UI component.
in MyCss.css
.trackTitle {
color:white;
}
in myComponent.js
import "./MyCss.css"
<Grid container item xs={1} className="trackTitle">
change color test
</Grid>
It doesn't change the color.
However the below works.
import "./MyCss.css"
<Grid container item xs={1} className="trackTitle">
<span className="trackTitle">
change color test
</span>
</Grid>
If I use basic tag span not Material-ui Grid
The class works.
See another case for component Slider
in MyCss.css
.mySlider {
height:"80px";
}
in myComponent.js
<Slider className="mySlider"
min={0} max={1} step={0.1}/>
not work.
<Slider className="mySlider" style={{height:"80px"}}
min={0} max={1} step={0.1}/>
works.
Now I understood className for component doesn't work.
Howeber, I want to use css to Material-UI component, how can I make it?
What you can do is to find the material-UI components CSS selector in the browser console, then override the css in your css file. Most likely this would work. Here is an example this is the root css for the slider
.MuiSlider-root {
color: #1976d2;
width: 100%;
cursor: pointer;
height: 2px;
display: inline-block;
padding: 13px 0;
/* position: relative; */
box-sizing: content-box;
touch-action: none;
-webkit-tap-highlight-color: transparent;
}
copy-paste it and then set your updates in the css
.MuiSlider-root {
/* update */
}
Material-ui is a css framework, if you want to use className for material-ui component
you have to injectFirst in root. example:
ReactDOM.render(
<StylesProvider injectFirst>
<App/>
</StylesProvider>
document.getElementById('root')
);
after this you will be able to use className anywhere on the app for any material-ui component

styled components / react

Im working on a simple button example which i plan to extend. I have added a new button and included some constants as well. so far so good. In case i want to use more button versions like version1, version2, version3 of the same button with some styles changed like the background color. How should i do that? And how should they be exported?
const PrimaryButton = styled.button`
font: inherit;
padding: 0.5em 1em;
border: 1px solid;
background-color: ${buttonBackgroundColor};
color: ${buttonColor};
border-radius: 0.25em;
border-color: ${colors.blueLight};
margin-right: 0.5em;
cursor: pointer;
outline:none;
:hover {
background-color: ${colors.blueLight};
}
`;
Maybe it is possible to extend the button (how?) or does it make more sense to add different components for each button? For my typography i have use "extend". That works. How would that be for the different button versions? Is there a similar way?
export const H1 = styled.h1`
font-size: 30px;
color: red;
`
export const H2 = H1.withComponent('h2').extend`
font-size: 24px;
`
It was working as i added a new component. I imported the PrimaryButton into the new defined component called "Version2".
import PrimaryButton from './primary';
From here i updated the PrimaryButton like this:
const Version2 = PrimaryButton.extend`background-color: red;`
This has the advantage that we have a master component for a button. Now we are able to extend the master with diversity of additional styles. In my case background-color.
With the help of
export default Version2;
we are now able to add this button called "Version2" into our render function like:
<PrimaryButton>ClickMe!</PrimaryButton>
<Version2>ClickMe!</Version2>
and now we get the different buttons. And it´s very modular and clean as well.

Categories

Resources