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

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>

Related

How to use Ant design v5 theme with style component

Antd 5.0 has been introduced their new theme system.
But I wonder how to access to those design tokens of theme when I declare a component by style-component.
normally I declare my component like this.
const MyComponent = styled.button`
color:${props=> props.theme.color.primary};
`;
theme here is getting from ThemeProvider of styled component that is defined in App.jsx
<ThemeProvider theme={baseTheme}>
<App/>
</ThemeProvider>
So, theme only can access to design tokens that were defined in theme file.
How can I access other tokens of Antd theme?
One way I'm thinking is creating a theme that overrides every single design token of Antd. But I think that's a bad idea
From the documentation consume-design-token, you can get and consume the token by using the theme.useToken() hook.
Create a ThemeProvider get the antd theme token and combine it with base theme, then pass the combined theme to the ThemeProvider of styled-components.
Then you can get the combined theme via passed props of styled-components.
theme-provider.tsx:
import { ThemeProvider } from "styled-components";
import { theme } from "antd";
import React from "react";
export default ({ children }: React.PropsWithChildren) => {
const { token } = theme.useToken();
return (
<ThemeProvider theme={{ antd: token, base: { color: "mediumseagreen" } }}>
{children}
</ThemeProvider>
);
};
App.tsx:
import styled from "styled-components";
import { ConfigProvider } from "antd";
import ThemeProvider from "./theme-provider";
const Button = styled.button`
color: ${(props) => {
console.log("props.theme: ", props.theme);
return props.theme.antd.colorPrimary;
}};
`;
export default function App() {
return (
<ConfigProvider
theme={{
token: {
colorPrimary: "red"
}
}}
>
<ThemeProvider>
<Button>Hello World</Button>
</ThemeProvider>
</ConfigProvider>
);
}
The log:
props.theme: {antd: Object, base: Object}
codesandbox

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.

can't change background color in theme Material-UI

I have been trying to define a custom theme using material UI and defining a default background colour for it. But the changes are not taking effect while other pallete options are working. Can anybody tell me what I'm doing wrong? As far as I can tell this is the way to change the colour.
Here's my code
theme.ts
import { createTheme } from '#mui/material';
import {red} from '#mui/material/colors';
const theme = createTheme({
palette: {
background: {
default: '#FFD600',
paper: '#FFD600',
},
},
});
export default theme;
my entry file
import '../styles/globals.css';
import {ThemeProvider} from "#mui/material/styles"
import theme from '../theme'
function MyApp({ Component, pageProps }) {
return (
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
);
}
export default MyApp;
EDIT: It seems to be changing the background for the components I have used with material-UI but not for other components I may define.
e.g. Here. I used the card component of MUI and the background was changed but I need it to change the background colour of the whole page
EDIT2: The component one worked because I defined paper colour, but I still cant get default to work
So the reason it's still not working is that we need to import CssBaseline for it to work. CssBaseline implements background.default color according to the doc.
Here's how it'll work
import '../styles/globals.css';
import {ThemeProvider} from "#mui/material/styles"
import theme from '../theme'
import { CssBaseline } from '#mui/material/';
function MyApp({ Component, pageProps }) {
return (
<ThemeProvider theme={theme}>
<CssBaseline/>
<Component {...pageProps} />
</ThemeProvider>
);
}
export default MyApp;
Still weird how the paper property works but for default you need to import additional dependencies

Material UI: Use theme in React Class Component

I am looking for something like ThemeConsumer (which probably doesn't exist). I've React component and I am using withStyles() higher-order component to inject custom styles. It's pretty well described in documentation but I didn't find any example which uses theme.
I have some base component which contains ThemeProvider. It means any of MUI components are being affected by it.
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const theme = getTheme(prefersDarkMode);
return (
<ThemeProvider theme={theme}>
...
</ThemeProvider>
)
I also use some functional components with makeStyles() to create styles with provided theme.
const useStyles = makeStyles(theme => ({
// here I can use theme provided by ThemeProvider
});
But it can't be used in class components. So I am using withStyles() HOC.
const styles = {
// I would like to use here provided theme too
}
export default withStyles(styles)(SomeComponent);
Summary of my question:
How do I use provided theme in class component?
withStyles supports similar syntax as makeStyles:
const styles = theme => ({
// here I can use theme provided by ThemeProvider
});
export default withStyles(styles)(SomeComponent);
Here's a simple working example:
import React from "react";
import { withStyles } from "#material-ui/core/styles";
import Paper from "#material-ui/core/Paper";
const StyledPaper = withStyles(theme => ({
root: {
backgroundColor: theme.palette.secondary.main
}
}))(Paper);
export default function App() {
return (
<StyledPaper className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</StyledPaper>
);
}
A component decorated with withStyles(styles) gets a special classes prop injected, which may be used for your custom styles. For example:
import { Box } from "#material-ui/core"
import { withStyles } from "#material-ui/core/styles"
const styles = theme => ({
myCustomClass: {
color: theme.palette.tertiary.dark
}
})
class myComponent extends Component {
render() {
const { classes, theme } = this.props
// In last line, you see we have passed `{ withTheme: true }` option
// to have access to the theme variable inside the class body. See it
// in action in next line.
return <Box className={classes.myCustomClass} padding={theme.spacing(4)} />
}
}
export default withStyles(styles, { withTheme: true })(myComponent)
If you pass { withTheme: true } option to withStyles HOC, you'll get the theme variable injected as a prop also.
If you have other HOCs (e.g. Redux's connect, Router, etc) applied to your component, you may use it like this:
export default withStyles(styles, { withTheme: true })(
withRouter(connect(mapStateToProps)(myComponent))
)
A more comprehensive explanation for this topic could be found in this article: Using Material UI theme variable in React Function and Class Components.
Use withTheme HOC
modified example from docs
import { withTheme } from '#material-ui/core/styles';
class DeepChildRaw
{
/*...*/
render()
{
return <span>{`spacing ${this.props.theme.spacing}`}</span>;
}
}
const DeepChild = withTheme(DeepChildRaw);
if are working with Class Components, you can use like here ;)
import React from 'react';
import Routes from './Routes';
import '../custom.css';
import { BrowserRouter } from 'react-router-dom';
import { MuiThemeProvider, createTheme } from '#material-ui/core/styles';
const theme = createTheme({
palette: {
primary: {
main: '#fff'
},
secondary: {
main: '#351436'
}
}
});
class App extends React.Component {
render() {
return (
<div className="App">
<MuiThemeProvider theme={theme}>
<BrowserRouter>
<Routes />
</BrowserRouter>
</MuiThemeProvider>
</div>
)
}
}
export default App;

Resources