How to make a layout with Styled Components? - reactjs

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.

Related

Material-UI ThemeProvider overwrites styles globally instead of only for wrapped components

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.

Can component styles be scoped instead of inline to prevent overwriting by multiple React apps on the same page?

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

Add style.css for a specific component in react

I'm trying to add a CSS file for a specific component in react, but the CSS file apply in all component
How can I add style.css for a specific component?
import React, { Component } from "react";
import { Link } from "gatsby";
import Layout from "../components/layout"
import Footer from "../components/Globals/Footer"
import "./crm2.css"
class Crm extends Component {
render() {
...
}
}
You can refer to this link on which the narrator is explaining the options you have for styling the React Components. Styling in React
Your options are
In-Line styling
Using variables
styling by means of a function or method inside the component
Once you take a look at the video link, you will know what approach suits you the best.
Your CSS className must be unique. If you write CSS for this class then it will be applied to the specified component.
There are two components in React
Built-in component (like <p>, <div>, <span>, etc)
React component (like <App/>,<Product>, etc)
React components allows you to break up the UI into different pieces so that it can then be reused and handled individually. It is the Dot-notation component like <UserContext.Provider> and any component which starts with a capital letter.
These components can be styled if you provide a unique className to those components and you write a CSS style for that.
You might have styled the built-in component as shown below
style.css file:
p {
font-size:14px;
color: red;
}
Using the above approach, the CSS would be applied to all the <p> component in all the JSX file.
If you have wanted to style the React component then you need to select those components and styled it as shown below.
<Product className = "items" />
CSS would be
.items {
color: red;
...
}

Why CSS is not applying correctly to button in react material web components?

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.

Material UI css load order

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>

Resources