Mui theme not applying if within a wrapper component - reactjs

With React (typescript) and MUI (5.4.2), I'm trying to put everything regarding styles within a single file, wrapping everything in my App.tsx.
Issue: The custom MUI theme does not apply to the rest of my app (fallback to default MUI theme)
The whole thing worked fine when the ThemeProvider component was placed directly within the App.tsx file, but broke as soon as I placed it elsewhere. I need to keep a separated component, for I'll add Elastic UI on top of MUI later on.
My App.tsx file:
function App() {
<UiProvider>
// ...whole app
</UiProvider>
}
The UiProvider component is a simple wrapper component as it follows:
import {ThemeProvider} from "#mui/styles";
import {CustomTheme} from "../../themes/CustomTheme";
import {createTheme, Theme} from "#mui/material/styles";
const UiProvider = (props: any) => {
return (
<ThemeProvider theme={CustomTheme}>
{props.children}
</ThemeProvider>
)
}
export default UiProvider

Because #mui/styles is the legacy styling solution for MUI, if this is for v5, perhaps the import for ThemeProvider should be:
import { ThemeProvider } from '#mui/material/styles';

Related

Why is my custom theme only partially applying (antd)?

I am using Ant Design in a React project of mine, and I am attempting to make use of their custom theming available in version 5 (5.1.2 installed) according to documentation here. However, the custom theme appears to only apply to certain components while skipping others altogether. In the below example, the darker background color is applied to the Content and Footer components while the Header and Sider components are left with the default color, and the Header and Footer components have updated foreground colors, but the Sider and Content components do not. What am I missing to make this theme apply in full to each of these components?
Example:
src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { ConfigProvider } from 'antd';
import theme from './theme';
import reducers from './reducers';
import App from './components/App';
const store = createStore(reducers)
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<ConfigProvider theme={theme}>
<React.StrictMode>
<App />
</React.StrictMode>
</ConfigProvider>
</Provider>
);
src/theme.js
import { theme } from 'antd';
const custom_theme = {
algorithm: theme.darkAlgorithm,
token: {
colorPrimary: '#e02820',
borderRadius: 5,
wireframe: false
},
}
export default custom_theme;
src/components/App.js
import React from 'react';
import { Layout } from 'antd';
const { Header, Footer, Sider, Content } = Layout;
class App extends React.Component {
render() {
return (
<Layout>
<Header>header</Header>
<Layout>
<Sider>sider</Sider>
<Content>content</Content>
</Layout>
<Footer>footer</Footer>
</Layout>
);
}
}
export default App;
Result:
I have been playing around with AntD custom theme as well and have found that not every attribute can be updated. The main changes allowed are colorPrimary and according to the documentation based on this color their algorithm chooses the rest of the color pallet that matches.
From documentation - "Brand color is one of the most direct visual elements to reflect the characteristics and communication of the product. After you have selected the brand color, we will automatically generate a complete color palette and assign it effective design semantics."
That being said you can try to be even more specific. By that I mean you can specify the style for each separate component.
<ConfigProvider
theme={{
components: {
Header: {
colorPrimary: '#00b96b',
},
Footer: {
colorPrimary: '#fff',
},
},
}}
>
Just change and add your desired styles to each component. If it still does not change, then that is the color AntD will let you have based for each component based on your choice of primary color.
Another option would be to use styled-components library to further provide the styles to AntD components that are not possible using Ants Config API.
If this provides the valid solution would you please click the green arrow on my response to inform others of the solution.

How to access MUI 5 theme variables in deep functional component?

The MUI 5 docs on Theming have a section on "Accessing the theme in a component". However, it's really just one sentence that links to the legacy style docs.
Here's the example they give in those legacy docs:
import { useTheme } from '#mui/styles';
function DeepChild() {
const theme = useTheme();
return <span>{`spacing ${theme.spacing}`}</span>;
}
Which is pretty much exactly what I want to do — I want to be able to access the theme color palette down in some deep functional component. However, my component complains
Module not found: Error: Can't resolve '#mui/styles' in...
Digging a little further, it seems they're rather strongly trying to discourage people from using this legacy Styles technique, and the MUI 5 way to do this is with "system design tokens", which I guess should Just Work. But, they're not.
I have my whole app wrapped in ThemeProvider:
import React from 'react';
import { CssBaseline } from '#mui/material';
import { ThemeProvider } from '#mui/material/styles';
import theme from './theme';
import Foo from './foo';
const App = () => {
return (
<Fragment>
<ThemeProvider theme={theme}>
<CssBaseline enableColorScheme />
<Foo />
</ThemeProvider>
</Fragment>
);
};
export default App;
And then in foo.js:
import React from 'react';
import { Box } from '#mui/material';
export const Foo = () => {
return (
<Box
sx={{
background: 'repeating-linear-gradient(-45deg, '
+ ' theme.palette.error.light, theme.palette.error.light 25px,'
+ ' theme.palette.error.dark 25px, theme.palette.error.dark 50px'
+ ')',
}}
>
<span>Test</span>
</Box>
);
};
I initially started with just error.light and error.dark. When that didn't work, I expanded it all to palette.error.light, etc..., and then ultimately to theme.palette.error.light, etc....
It seems no matter what I try, it's not accessing those theme variables, and is instead just passing through the text.
So, back to the question: how am I supposed to access MUI 5 theme variables in nested functional components?
Replace
import { useTheme } from '#mui/styles';
with
import { useTheme } from '#mui/material/styles';
#mui/styles is used for legacy, you can add it using yarn add or npm install, but first give a shot to what I mentioned above.

How to apply my custom themes with ConfigProvider in Ant Design?

We are developing a using interface with React and Ant Design. We would like to override the default theme and colors. As an example we defines an array called themes. There is 4 differents themes as object. I defined a button to change theme. Reading the official docs I have included the following code in App.js to override the default theme but no success.
ConfigProvider.config(
{
theme:theme
}
)
Can anyone help me to override the default theme without less or anything else but just with ConfigProvider?
import "./App.css";
import "antd/dist/antd.css";
import { ConfigProvider } from "antd";
import { ThemeProvider } from "styled-components";
import ChangeTheme from "./components/ChangeTheme";
import { useContext } from "react";
import { AppContext } from "./_context";
const App = () => {
const { theme } = useContext(AppContext);
ConfigProvider.config({
theme: theme,
});
return (
<ThemeProvider theme={theme}>
<ConfigProvider>
<div className="App">
<ChangeTheme />
</div>
</ConfigProvider>
</ThemeProvider>
);
};
export default App;
First Step
you need to import antd.variable.min.css in one of your root files, like src/index.js which is recommended in the document,
import 'antd/dist/antd.variable.min.css';
Second Step
you also need to import antd's ConfigProvider in src/index.js:
import { ConfigProvider } from 'antd';
Third Step
then you need to modify the theme variables in config method of ConfigProvider like below:
ConfigProvider.config({ theme: { primaryColor: "#f00" } });
ps the vriables that you can modify in theme are:
primaryColor
errorColor
infoColor
processingColor
successColor
warningColor
Fourth Step
finally you wrap ConfigProvider around the <App/> component in src/index.js
<ConfigProvider>
{/* some other codes you might have */}
<App />
</ConfigProvider>

Use style functions for material-ui components besides Box

I'm just starting with Material UI. Thanks for bearing with me.
I know you can use things like <Box mx={2}> out-of-the-box (ha). So if I wanted to put a margin around, say, a TextField, I could wrap it in a box.
Is there a simple way to set up my app's theme so that any component can use those style function props? (m, p, display, etc)
So that I could to <TextField mx={2}/> without having to wrap it in a Box.
The docs imply that you can do this:
(the example uses ThemeProvider from styled-components but I'm assuming that MUI's ThemeProvider works the same way???)
import React from 'react'
import { ThemeProvider } from 'styled-components'
const theme = {
spacing: 4,
palette: {
primary: '#007bff',
},
};
export default function App() {
return (
<ThemeProvider theme={theme}>
{/* children */}
</ThemeProvider>
)
}
I've tried this but it crashes from the TextField's my prop:
import { createMuiTheme, TextField, ThemeProvider } from '#material-ui/core';
// Greatly simplified version of my component
const App = () => <TextField my={2}/>
let theme = createMuiTheme({})
export default () =>
<ThemeProvider theme={ theme }>
<App/>
</ThemeProvider>;
I can do something like this and it works:
function App() {
const Input = styled(TextField)(compose(spacing))
return <Input my={3}/>
}
But then I'd have to compose my components every time I want to do use the style functions.
The docs are showing how the theme can parameterize the Box features (e.g. such that a spacing unit is 4px instead of 8px) -- the theme doesn't do anything to enable those features.
Material-UI is intending to support #material-ui/system features on core components in v5, but that is still months away.
Your main options are doing something like you showed in your example (though you should move const Input = styled(TextField)(compose(spacing)) to the top-level rather than doing this within render of App). You could put this in a separate file and import this component instead of TextField whenever you want to use those features. For instance:
MyTextField.js
import TextField from "#material-ui/core/TextField";
import { styled } from "#material-ui/core/styles";
import { compose, spacing } from "#material-ui/system";
export default styled(TextField)(compose(spacing));
App.js
import React from "react";
import TextField from "./MyTextField";
export default function App() {
return (
<div className="App">
<TextField variant="outlined" label="Material-UI system demo" />
</div>
);
}
Another option is to use Box with the clone prop and wrap the component you want to style. For instance:
import React from "react";
import TextField from "#material-ui/core/TextField";
import Box from "#material-ui/core/Box";
export default function App() {
return (
<div className="App">
<Box my={3} clone>
<TextField variant="outlined" label="Box demo" />
</Box>
</div>
);
}
You can also use the component prop of Box:
import React from "react";
import TextField from "#material-ui/core/TextField";
import Box from "#material-ui/core/Box";
export default function App() {
return (
<div className="App">
<Box my={3} component={TextField} variant="outlined" label="Box demo" />
</div>
);
}
Related answers:
Material-UI Grid does not hide whe use Display
Dynamic icon size in Material-UI
Box vs className vs style for vertical spacing in Material UI
Reusable component using theme-based Box features
Using Material-UI Box Component with the Drawer Compoment
How to use override Button using Box component in Material-UI?

Duplicate style render on SSR

I'm currently developing CMS with Gatsby and emotion.
Style is duplicately generated even same class is allocated.
I think there's multiple of solution(like using postCSS), but I'd like to grasp the cause of it.
import React from 'react';
import PropTypes from 'prop-types';
import tw from 'twin.macro';
import styled from '#emotion/styled';
const StyledComponent = styled.section``;
const Section = ({ component: Component, children, ...other }) => (
<StyledComponent css={tw`bg-white`} {...other}>
{children}
</StyledComponent>
);
Here's rendered result on browser(CSS Style is literally duplicated)
Above problem occurs only in production environment.

Resources