I am having hard time understanding how I should structer my project.
I am using react with material UI and css modules.
Problem is that god knows why, all styling from MUI loads at the bottom of the header same as css module styling.
After some research I found two solutions:
Use !important inside css modules which is terrible.
Changing the injection order https://material-ui.com/guides/interoperability/#css-modules
Problem with the second one is that it would be terrible tedieouse in a multi component project where every time you introduce a new component you have to load it manually as in the example. Am I missing something obvious? Do you have any ideas how to easier change the load order?
According to the Material-UI documentation, you should add a <StylesProvider/> component, which wraps your component tree.
import { StylesProvider } from '#material-ui/core/styles';
<StylesProvider injectFirst>
{/* Your component tree.
Styled components can override Material-UI's styles. */}
</StylesProvider>
If injectFirst is set (and true of course), the Material UI style tags will be injected first in the head (less priority)
I think you may be misunderstanding something in the example. There isn't anything you need to do on a per-component basis to change the load order.
The steps are as follows:
1. In your index.html add a comment like <!-- jss-insertion-point --> into the head where you would like the jss CSS to be inserted.
2. In your index.js (or somewhere at or near the top of your rendering hierarchy) create the jss configuration to indicate the name of the insertion point comment:
import JssProvider from "react-jss/lib/JssProvider";
import { create } from "jss";
import { jssPreset } from "#material-ui/core/styles";
const jss = create({
...jssPreset(),
// We define a custom insertion point that JSS will look for injecting the styles in the DOM.
insertionPoint: "jss-insertion-point"
});
3. Wrap your top-level element in the JssProvider to put those configurations in play (no component-specific steps):
function App() {
return (
<JssProvider jss={jss}>
<div className="App">
<Button>Material-UI</Button>
<Button className={styles.button}>CSS Modules</Button>
</div>
</JssProvider>
);
}
I've created a CodeSandbox similar to the one pointed at by the Material-UI documentation except that this one uses the create-react-app starting point, so the dependencies are simpler.
In version 5 MUI changed the import and some components became deprecated.
By default, the style tags are injected last in the <head> element of the page. They gain more specificity than any other style tags on your page e.g. CSS modules, styled components.
Not in the documentation, but the StyledEngineProvider component has an injectFirst prop to inject the style tags first in the head (less priority):
<StyledEngineProvider injectFirst>
<MUIThemeProvider theme={theme}>
{children}
</MUIThemeProvider>
</StyledEngineProvider>
Related
I found a couple of ways to import bootstrap into my project. I'm rather unsure if there is a best practice.
I installed bootstrap and react-bootstrap using npm.
Option 1: Import every component seperately
import Button from 'react-bootstrap/Button'
function App() {
return (
<div className="App">
<Button variant="outline-secondary" id="button-addon1">
Button
</Button>
</div>
);
}
vs. Option 2: Import everything
import * as bs from 'react-bootstrap'
function App() {
return (
<div className="App">
<bs.Button variant="outline-secondary" id="button-addon1">
Button
</bs.Button>
</div>
);
}
My guess:
Option 1 is leaner as it only imports the component I use. But is it the best way to use it? Especially when Prototyping out a quick idea it can get filled with imports quickly or can be a pain to import everything hand by hand.
Any advice is very welcome! Thank you!
Personally I would go with Option 2. Bootstrap's components names are very generic and could be confused with other components.
Importing the specific component from the library rather than importing everything improves the performance while fetching and rendering.
However,
You can also import multiple components from a single import statement
import { Form, Col, Button } from "react-bootstrap";
You can also use the default react-bootstrap syntax to import
It imports dynamically without naming the specific components
import * as ReactBootstrap from "react-bootstrap";
return (
<ReactBootstrap.Button bsStyle="success" bsSize="small">
Button
</ReactBootstrap.Button>
);
So, In terms of performance, multiple components imports or individual component imports are way better than the others.
You can just include the link to the CSS and JS bundle in the public/index.html
You can find the CSS link here -> https://getbootstrap.com/docs/5.0/getting-started/introduction/
Copy the CSS code and paste it into the head tag
You can find the JS bundle here -> https://getbootstrap.com/docs/5.0/getting-started/introduction/
Copy the JS Bundle code and paste it right on top of the end of the body tag. Like this 👇
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"> //This is the JS Bundle
</script>
</body>
You can just use the bootstrap class names on className of the component which will be easier to refer on the bootstrap docs.
<div className="d-flex mx-2 bg-dark"></div> //Usage of bootstrap classes
There are default imports (option 1) and named imports (option 2). Generally, the main difference is that with option 1 you import only the component, not the whole library: https://react-bootstrap.netlify.app/getting-started/introduction/#importing-components
You should import individual components like: react-bootstrap/Button
rather than the entire library. Doing so pulls in only the specific
components that you use, which can significantly reduce the amount of
code you end up sending to the client.
import Button from 'react-bootstrap/Button';
// or less ideally
import { Button } from 'react-bootstrap';
I said generally, because you can set up your bundle tool for tree shaking. With tree shaking you remove everything, that is not used in your code, resulting in the same bundle size, as you would import only certain components directly via default imports.
I use option 2, because I like to clip all the imports from the same library. It's also easier for eyes to parse the imports IMO.
I have a React Component with multiple Material-UI Selects. Now I wanted to overwrite some styles of one of them so I created a theme and now want to apply it wit the ThemeProvider.
My problem is that the ThemeProvider overwrites the styles of every Select and not only of the one it is wrapped around.
When googling I found a lot of questions how to make ThemeProvider apply its overwrites globally but that is the opposite of what I am trying to do. I want the ThemeProvider to apply its overwrites only to the Components, that it wraps around.
Is there a better alternative to using ThemeProvider in my usecase? If yes, it has to work with class based Components (because I am using one here)
Codesandbox that shows my problem: https://codesandbox.io/s/twilight-sun-vyl9i
I am fairly new to Material-UI, so forgive me if I do something fundamentally wrong.
I had the same problem in V4 and had to resolve it another way.
The parent <ThemeProvider> with no theme prop solution wouldn't work with Typescript because the theme prop is required.
If anyone needs a solution that works with Typescript, I resolved it using StylesProvider. By wrapping each ThemeProvider in a StyleProvider with a different seed, your theme will no longer interfere with any other components outside of the StyleProvider.
Like so
import { ThemeProvider, StylesProvider } from '#material-ui/core/styles';
//...
<StylesProvider generateClassName={generateClassName}>
<ThemeProvider theme={theme}>
<children>
</ThemeProvider>
</StylesProvider>
You'll want to create a generateClassName prop to pass in:
import { createGenerateClassName } from '#material-ui/core';
const generateClassName = createGenerateClassName({
seed: 'blue-select,
});
export default generateClassName;
OK, I found the solution myself. According to this issue on the material-ui github , there is a v4 bug that multiple ThemeProviders must have a parent ThemeProvider element. According to them it will be fixed in the upcoming v5.
So what I did, I just wrapped a <ThemeProvider> around my <div className="App"> without giving it a theme prop.
I have an app with html:
<div id="react-root-navbar"></div>
<div id="react-root-body"></div>
and corresponding React components that call React.DOM.render on each div.
Both React components use Material UI components. Thus, a set of inline styles are injected for each component.
The problem is that all styles for the second component will be further down in the HTML than for the first component, thus these CSS rules will be higher priority. This interrupts the intended cascading flow and results in lots of incorrect styling. For example, .MuiAppBar-colorPrimary is overruled by .MuiPaper-root:
I know that the ideal solution would be to have all components within a single React app and prevent duplciate imports in the first place. This isn't possible with the codebase I'm working with, however, which uses a Django frontend migrating one piece at a time to React.
Is there any way to make the styling exported by Material UI for each component scoped specifically to that component, so that the styles do not overwrite each other?
MUI has a component StylesProvider that allows you to adjust how styles are added. StylesProvider has a prop generateClassName to which you can pass a generator to determine how class names are generated.
You can create a generator using a MUI function createGenerateClassName, to which you can pass the option disableGlobal to add simple suffixes to class names so that each app will have scoped CSS applied to it.
I was already wrapping all MUI components in a component MUIThemeProvider to use the MUI component ThemeProvider. I just added StylesProvider to this wrapper:
const generateClassName = createGenerateClassName({
disableGlobal: true,
});
return (
<StylesProvider generateClassName={generateClassName}>
<ThemeProvider theme={theme}>
{props.children}
</ThemeProvider>
</StylesProvider>
)
Since the point of React is to make components reusable, and the layout of a page can change drastically from one app to another, I'm not sure where to put my layout-specific styles. Any suggestions?
The placement of a component should be decided by the 'consumer' of the component. So, for example, if you have 3 components:
ComponentA
ComponentB
ComponentC
ComponentC would decide the placement all its sub-components.
ComponentB would decide the placement all its sub-components, which
would include ComponentC
ComponentA would decide the placement all its sub-components, which
would include ComponentB
If you mean global styles in React you have two options:
option 1 : throw them in as a regular CSS file - see how Create-React-App does it - or just add them to you index/html where you're rendering the app.
option 2: Styled Components has support for Theming, meaning they give you a <ThemeProvider /> element and then you can use the provided styles in any component downstream. Here are the docs including a basic example.
If on the other hand you're referring layouts but on a component / sub component level, you basically pull the layout styles as far up as you can. An example would be having a element with its own styles; something like this:
// Layout.js
const myStyledContainer = styled.div`
display: flex;
`
export default (props) => <myStyledContainer>{props.children}</myStyledContainer>
Then in you App.js you'd have something like:
return (
<Layout>
*... your other components or pages or whatever*
</Layout>
It's a matter of opinion so just try things and see what works for your project.
I am new to React, I have some confusion related to CSS styling related to rwmc components.
I am just rendering two Button components on web page by importing it from '#rmwc/button' package. I am following this tutorial
https://jamesmfriedman.github.io/rmwc/buttons
I have also imported material design for this component like
import '#material/button/dist/mdc.button.css';
Now I have two buttons on my screens, for one of the button component, I have mentioned className property. In that class button color is just getting red which is working fine but I am wondering here, besides changing color of button, all other css defined in mdc.button.css are just getting applied to this as well, I don't know why is it happening so, Is this a correct behavior.
I am asking this because I have read here that
https://jamesmfriedman.github.io/rmwc/styling-theming
All of the components have the material-components-web classNames on them and you can add your own which means you are changing main class.
Any help will be appreciated.
Code:
import React from 'react';
import ReactDOM from 'react-dom';
import { DrawerHeader } from '#rmwc/drawer';
import { Button, ButtonIcon } from '#rmwc/button';
import '#material/button/dist/mdc.button.css';
//import styles from './index.module.css';
import './index.css'
const MyComponent = props => (
<div>
<Button>Default</Button>
<Button className="myDrawerHeader">Default2</Button>
</div>
);
ReactDOM.render(<MyComponent />, document.getElementById('root'));
index.css
.myDrawerHeader {
color: red !important;
}
Output on the screen is coming this which I think is wrong. Why all other styles from .mdc are getting applied to second button, I have just changed color of it.
screen-output-now
I think the behavior here is correct. Both the buttons have material-components-web css className and what you are doing is, adding another class to it. You are not actually changing the main class, you are extending the css styles of the second button using another class.
It behaves underneath as,
<button className="material-components-web">Default</button>
<button className="material-components-web myDrawerHeader">Default2</button>
I agree with Vishmi Money, the behavior is expected. When looking at the source code of the lib you used, its appeared a comment for classname props,
https://github.com/jamesmfriedman/rmwc/blob/master/src/button/index.js
/** Additional className for the button */
className?: string
So I think the idea is beside default classes you can define your own class and if you want to override some default behaviors then you can write it in your own class.