I'm attempting to use ready-made themes for Bulma components (https://jenil.github.io/bulmaswatch/) in my React app, in a way that allows the user to toggle between them (specifically, between Flatly and Darkly).
I can import one theme at a time, but can't figure out how to implement switching between the contents of two .css files. I have attempted searching, but I only find generic solutions for very basic custom themes that do not seem to be suitable for switching between ready-made themes.
Below is an example of the kind of stuff I find, but I don't know how to scale it up to using two 100kb+ .min.css files.
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext( themes.dark // default value);
Related
I'm using chakraUI in my React project. I have some custom buttons, texts, alerts and more components.
Is there a way to customize something like the following.
components: {
Button: {
primaryDefault: {
colorScheme: '#5c186a',
size: 'lg',
border: '2px',
},
//more customize buttons
}
}
I have my theme.js with the import { extendTheme } from '#chakra-ui/react'; and the configuration from the chakra's documentation link here. But I can't be able to use my own customize buttons, do you know how to use this?
Also, in my extendTheme file I was trying to do something like this:
colors: {
primary: {
dark: '#5c186a',
light: '#7c4188',
},
secondary: {
yellow: '#fdb813',
red: '#d6075b',
blue: '#007ac3',
},
//more colors
}
And if I want to use them in the same file for customize other elements I don't know how to reference them. If I want to use primary dark color in some button I tried to use
colorScheme: this.colors.primary.dark
But it throws me an error :(
I have a classic atoms/molecules/organisms monorepo with storybooks in order to create a custom components library. At the same time, such a library is based on MUI which has applied a custom theme. All of this is built with TypeScript.
I decided to base our library on MUI because it could be easier and faster for us to develop our custom components, but while I'm saving time on making them I'm putting the rest of my time trying to fix issues with the built :(
The theme
On atoms repo I have added our custom theme json which is imported by other repos (molecules and organisms) and it also gets exported as part of the atom's library and can be applied on an external project.
It uses a basic MUI as a base theme, which has been updated with some branding changes and also some custom colours (here is the problem). To make those custom colours available I have created a createPalette.d.ts file on the same Theme/ folder to declare the additions:
import '#mui/material/styles';
declare module '#mui/material/styles' {
interface Palette {
myColor: Palette['primary'];
}
interface PaletteOptions {
myColor?: PaletteOptions['primary'];
}
}
// Updated Button's props so it allows the color
declare module '#mui/material/Button' {
interface ButtonPropsColorOverrides {
myColor: true;
}
}
The them is then applied to each repo's .storybook/preview.js file like follows:
import { ThemeProvider as MUIThemeProvider, createTheme } from '#mui/material/styles';
import { ThemeProvider } from 'emotion-theming';
import theme from '../stories/Theme';
import { withThemes } from '#react-theming/storybook-addon';
const providerFn = ({ theme, children }) => {
// this fixes some issues between emotion and mui theming
const serialTheme = JSON.parse(JSON.stringify(theme));
const muiTheme = createTheme(serialTheme);
return (
<MUIThemeProvider theme={muiTheme}>
<ThemeProvider theme={muiTheme}>{children}</ThemeProvider>
</MUIThemeProvider>
);
};
const themingDecorator = withThemes(null, [theme], {
providerFn,
});
export const decorators = [themingDecorator];
And it all works just fine. I can make use of the MUI components and my theme easily.
Well, not exactly....
The problem
While I can access the theme from any other repo, it seems to fail to find the custom colours declaration and therefore every time I try to use something like theme.palette.myColor.main (as per our sample above) I get a
Property 'myColor' does not exist on type 'Palette'.ts(2339)
I have found out that, obviously, if I just replicate createPalette.d.ts on, let's say, molecules repo, it doesn't complain when I use it and also it autocomplete it with its main, dark, light... options. However, it does still through an error on 'build':
stories/ComponentFolder/index.tsx: error TS2339: Property 'myColor' does not exist on type 'Palette'.
My thoughts
What I think would be the most obvious solution is to import/extend createPalette.d.ts on any other repo but I don't seem to find a way of doing so, but also then there is the problem when building.
I'm not convinced this will work if I import the theme on any other project because maybe it would complain again about the property not existing on type 'Palette'.
I might as well just be doing this all wrong and the Theme should be stored and applied in a different way. What would be the best approach for something like this?
Notes
I'm also exporting the Theme as part of my library because I have also not been able to find a way of building and publishing my library with my theme applied. At the moment I am importing it: import theme from '#mylibrary/atoms/lib/Theme' and applying it with <ThemeProvider />. In some way, it's basically the same problem but instead of affecting other repos within my monorepo, it's affecting any other react app that tries to make use of the library.
I really, really hope someone can shed some light on this or share their way of creating something similar, please :D
I think that you are importing an interface and using it as a theme, pretty sure that you need to use a theme object like it is shown here in Using with Material-UI
const theme = {
palette: {
primary: {
main: '#556cd6',
},
secondary: {
main: '#19857b',
},
error: {
main: red.A400,
},
background: {
default: '#fff',
},
},
};
Material UI's default theme ships a palette of colors, including a special set of dark colors (docs, code).
What makes these dark mode colors special is components who consume them don't need to depend on knowing the theme's palette.mode (aka light/dark mode) - they update automatically.
codesandbox demo
My goal is to extend this set of colors, such that components I write can use new colors beyond this built-in set, e.g. theme.palette.myColor and benefit from the same automatic behavior.
In other words, I don't want to have dark mode logic be duplicated in each theme-consuming component:
const WhatIDontWantComponent = () => (
<Box
sx={{
color: (theme) =>
theme.palette.mode === "light"
? theme.palette.myColor.light
: theme.palette.myColor.dark,
}}
/>
);
I instead want to use
const WhatIWantComponent = () => (
<Box
sx={{
color: (theme) => theme.palette.myColor
}}
/>
);
So myColor would be included in the light/dark set that already exists, and benefit from this automatic behavior.
Possible? Is there some way to accomplish this within my app without patching MUI in some way to accept custom colors?
deps
#material-ui/core version 5.0.0-beta.4
react, react-dom 17.0.2
next.js 11.0
Ended up going with this:
const baseTheme = createTheme({...common options...})
export const lightTheme = createTheme({ ...light specific...}, baseTheme)
export const darkTheme = createTheme({ mode: "dark", ...dark specific...}, baseTheme)
based on this discussion.
We basically perform theme composition in multiple steps + utilizing how the second arg to createTheme() gets deepmerge'd.
Once you have the two themes, you could consider setting up a toggle by bringing your own mode:
<ThemeProvider theme={mode ? lightTheme : darkTheme}>
{...app...}
</ThemeProvider>
This works, but IMO a downside of this approach though is that I have two themes and have to manage dark/light state externally. Not a huge problem but feels a bit redundant -- in my mind dark/light mode seems like a concern that could (should) be handled internally to a single theme.
Perhaps there are good reasons against, but IMO it feels more ergonomic if MUI would allow users to specify our own dark palette, like I asked in my original question, vs the current hard coded one.
So if you're looking for custom MUI dark colors, this approach seems to be the best one given the situation right now.
You can customize the material-ui theme using theme provider component in order to add your custom colors for e.g,
import { createTheme, colors } from '#material-ui/core/styles';
const theme = createTheme({
palette: {
background: {
default: "#F6F7FF",
paper: colors.common.white
},
primary: {
main: "#43A047"
},
secondary: {
main: "#43A047"
},
text: {
primary: "#000000",
secondary: "#6b778c"
},
// Add your custom colors if any
},
});
You can write this configuration code inside a separate file and then import it into your root component file.
import theme from "src/theme";
import { ThemeProvider } from "#material-ui/core";
<ThemeProvider theme={theme}>
<YourRootComponent />
</ThemeProvider>
Then consume it the same way you do it for the default material UI colors
Also, you can customize typography, shadows, override default class, and much more check out this
I know we can edit the theme of material UI but I was thinking on making it dynamic, where in we can have SASS Variables set, and it will automatically update the Material UI theme.
I use sass to design my page, and here's the sample of variables I use:
$primary-color: #1E79C7;
$secondary-color: #E5681A;
Currrently for me I do the following for the material ui button, because i want my design to be on one place as much as possible
.app-button-blue {
background-color: $primary-color !important;
margin: 5px;
}
.app-button-gray {
background: transparent !important;
box-shadow: none !important;
}
.app-button-white {
background: transparent !important;
box-shadow: none !important;
border: $primary-color solid 1px !important;
}
Is there a way for me to use this SASS variables on overwriting the theme of material ui - like setting the primary and secondary colors?
Material UI uses a javascript based style solution (JSS) instead of a CSS pre-processor like SCSS (see style solution).
This means its not possible to customize the Material UI theme via SCSS variables. Nor is it possible to access the theme in your CSS/SCSS styles.
If you want to use SCSS for styling/theming, you might consider Material Web Components instead.
It is possible to populate the MaterialUI theme from Sass/Scss variables using Webpack wizadry
palette.scss
$primary: #1E79C7;
$secondary: #E5681A;
:export {
primary: $primary;
secondary: $secondary;
}
theme.js
import { createMuiTheme } from '#material-ui/core/styles'
import palette from './palette.scss'
export const theme = createMuiTheme({
palette: {
primary: {
main: palette.primary,
},
secondary: {
main: palette.secondary,
},
}
})
App.js
import React from 'react'
import { ThemeProvider } from '#material-ui/core/styles'
import { theme } from './theme'
export const App = () => {
return (
<ThemeProvider theme={theme}>
// App
</ThemeProvider>
)
}
This means you can use Sass to style and color both your non Material UI and Material UI components from one source of truth
To style other components, just use Sass imports
#import './palette.scss'
.app-button-blue {
background-color: $primary; // removed !important cos there's usually a better way
margin: 5px;
}
An example on this GitHub issue suggests how you can do this.
import React from 'react';
import { withStyles } from '#material-ui/core';
const cssVariables = (theme) => ({
'#global': {
':root': {
'--color-primary': theme.palette.primary.main,
'--color-secondary': theme.palette.secondary.main,
}
}
});
const RootComponent = () => {
return <div>Whatever...</div>
}
export default withStyles(cssVariables, RootComponent);
Having in mind RootComponent initialises inside ThemeProvider.
There's a way to define the theme variables in the JS-side and use them in the CSS-side to keep a single source of truth and allow dynamic theme switching. You can check the solution I posted on the MUI GitHub repository.
It may not be exactly what you wanted to achieve, but the following article explains how you can export SASS variables. https://til.hashrocket.com/posts/sxbrscjuqu-share-scss-variables-with-javascript
Afterwards you can import these in JS and use them to set up your theme.
Initialize your variables in the <body> tag styles.
body {
--my-var: #fff;
}
Then it will be visible for Material UI Drawers and other components, that opening with portals.
UPD 2:
There is another way to do the thing above dynamically. So, if you want to use CSS Variables to change Material UI components styles, for example - for Drawer (that uses React-Portals to lift up a component to top level of the DOM). The problem was that by MUI lifted up components were out of the 'root' div and CSS Variables could not reach these components.
Solution:
const [theme, setTheme] = useState('light');
useEffect(() => {
document.body.classList.remove('dark', 'light');
document.body.classList.add(theme);
}, [theme]);
and add variables to these classNames in some file.
File theme.scss:
.light {
--theme-color: #A80000;
--theme-page-background: #FFF;
$theme-page-background: #FFF;
--theme-page-text: $color-text;
}
.dark {
--theme-color: #0000A8;
--theme-page-background: #111;
$theme-page-background: #111;
--theme-page-text: #FFF;
}
Import your theme.scss file to the project and it have to work.
This questions targets material-ui 1.0.
When I create a theme with createMuiTheme, how can I set, for example for typography.title, different styles for different breakpoints? On a component level I can achieve this with something like this:
const styles = theme => ({
title: {
fontSize: 34,
},
[theme.breakpoints.down('sm')]: {
title: {
fontSize: 28,
}
},
})
Material-ui sure has a lot of different theming solutions. When you look for one that would be useful to you, you are looking for two things:
Creating a theme that can be applied to component hierarchy.
Doc page "Nesting the theme"
Changing single styling rules while keeping the others intact.
Doc page "Customizing all instances of component type"
and "Typography API"
The key to make it work is to create a second theme that can see the breakpoints, and provide it with some special options for overriding typography:
...outerTheme,
overrides: {
MuiTypography: {
title: {
[outerTheme.breakpoints.down("sm")]: {
fontSize: 28
},
}
}
}
I find the "Nesting the theme" example code suitable to test it on, so this is what it could look like:
codesandbox.io/s/98192p85zy
EDIT: replaced the final code link to make it more useful an answer than just the examples from the docs.
There is another way to work with createMuiTheme with the breakpoints methods.
If you check the createMuiTheme core, you will see that it uses the createBreakpoints class.
So, you can do like that:
// theme.js
import createBreakpoints from '#material-ui/core/styles/createBreakpoints'
import { createMuiTheme } from '#material-ui/core/styles'
const breakpoints = createBreakpoints({})
const theme = createMuiTheme({
overrides: {
MuiTab: {
root: {
[breakpoints.up('lg')]: {
minWidth: '200px',
backgroundColor: 'yellow',
},
},
wrapper: {
padding: '0 10px',
backgroundColor: 'black',
},
},
},
})
export default theme
(tested: #material-ui/core 4.0.1)