Loading Post...
Loading Post...
demo link: https://mui-theming.vercel.app/
code repo: https://github.com/facinick/MuiTheming
Night
and Dark
(default value taken from user system, also reacts to user system theme changes).<Button color=’google’ />
and button knows what background and text colour to use.Create a new react typescript app with create-react-app by running
npx create-react-app awesome --template typescript
in a terminal window,
NOTE: this will create an app named awesome as given in the command… you can go ahead and give it whatever name you like for ex npx create-react-app spiderman --template typescript
will create an app named spiderman (reference: https://create-react-app.dev/docs/adding-typescript/ )
Great, now CD into the newly created app. (use whatever app name you gave instead of my-app)
cd ./awesome
Now open the repo in an IDE, for example if you’re using VSCode and you’ve setup it’s command in your PATH, run
code .
(notice the full-stop that tells VSCode to open project in current directory, i.e. the directory we CDed into)
your project should look similar to this
Go ahead and enter the following command in terminal to start the project and have our react app run in live reload mode in the browser
npm run start
or yarn
yarn start
If all worked properly, you should be seeing a Pop culture atom symbol of React!
next, we are going to install MUI packages that uses ‘styled’ as its theming engine.
Now we are going to install MUI 5 dependencies (reference: https://mui.com/material-ui/getting-started/installation/)
npm install @mui/material @emotion/react @emotion/styled @mui/icons-material
or yarn
yarn add @mui/material @emotion/react @emotion/styled @mui/icons-material
Done, that should be all the packages we need to build our theming demo.
next, we are going to create a theme provider (sort of a store that will have our theme to use anywhere in our app and provide us functions to change theme from anywhere in our app).
Now we are going to create a Context Provider component, which will provide our various themes (red blue default green - light/dark) to our entire app. This works on react context api under the hood. More on react context api: https://reactjs.org/docs/context.html
As the react docs say: Context provides a way to pass data through the component tree without having to pass props down manually at every level.
So now once we provide our theme at the top most level, we can directly use it anywhere in our app. You’ll see more of its working later in this tutorial.
Create a file called MyThemeProvider.tsx
in the following path: src/theme/MyThemeProvider.tsx
Add the following code to it:
This is our boilerplate for our Theme Context Provider
typical flow: MUI renders components with default theme → User changes theme → new theme is sent to MUI → MUI re renders it’s components with new theme
ℹ️ note: do not miss GlobalStyles and CssBaseLine components.
CssBaseline use: https://stackoverflow.com/a/59145819/17449710 [very imp]
GlobalStyles use: https://stackoverflow.com/a/69905540/17449710 [less imp]
Sure we will use our theme to provide colours to buttons and various components but we can’t change our App’s background and font color dynamically (technically that can be done but this is the MUI way). CssBaseline provides this functionality to manage background and text color of our app automatically based on what theme we provide it. (ex body html tag)
GlobalStyles just retains the page’s default css that gets reset/removed by CssBaseline. (ex body has a margin of 8px by default .. or something)
Don’t worry if you are not understanding this, once we are done building our demo, you can try remove those components to see what difference does it make to our app.
note: we still haven’t provided
to our context above, so it’s essentially useless at the moment. first we will connect this to our app and then we will add functionality to it so we don’t have to deal with connecting stuff later.
Now be a good human and head over to src/index.tsx
It must look similar to this as of now:
We are going to provide our Context store here by wrapping <App />
with ThemeProvider
that we exported earlier and StyledEngineProvider
from @mui/material/styles
package
Below is the updated code in this file src/index.tsx
, follow along the comments to know what is done:
Now that we have connected out Context provider, let’s add in our functions to change theme and also the theme itself that’s to be used by our components
head over to src/theme/ThemeProvider.tsx
we are going to have two react states: theme (0=red,1=blue,2=green,3=default) and mode (light, dark)
Below is the updated code in this file, follow along the comments to know what is done:
Once this is done, now all that’s left is
How material UI’s theming works is, there is a theme palette object that contains colours for everything. App background, text that’ll appear on app background, primary colours, text colours to use when background is of primary colours, basically everything is predetermined. From fonts to spacings to colours to everything.
Head over to https://mui.com/material-ui/customization/default-theme/ to checkout the default theme palette object and it’s values for light and dark mode. This is the default set of values you get, for example when you add color={’primary’}
props to a MUI Button, this theme object tells what button background and its text is going to look like. Expand the palette
key of the entire theme object. That’s what we will be tweaking to create a set of colours.
Now checkout theme.palette.primary
key, whose value is an object with four keys namely main, light, dark, contrastText.
when you set color={’primary’}
to your button, it applies the main colour to its background and contrastText to its foreground like text color. You can also tell MUI to use light or dark variants of your main colour.
This means if we need to create additional themes, lets say a reddish theme named Dracula… we will have to decide most of these default values (if not all) for light as well as dark modes (the above screenshot is of light mode theme palette object)
How do we decide what values to put for our Dracula theme and ensure we don’t mess up accessibility?
One fun way (not the only) that I’ll show you is as follows:
Head over to https://material-foundation.github.io/material-theme-builder/#/custom , click on Custom
now from the left most panel, click on Primary, select any colour you like. This will generate an entire palette to use for you on the right side.
Like so:
What does this mean? How will it help us colour our components and pages?
imagine a homepage,
It’ll take background colour of background and font colour of onBackground (from the above image)
A card on homepage will take background colour of primaryContainer and font colour of onPrimaryContainer
A button on that card will take background colour of lets say primary and text on button will take font colour of onPrimary
all of this is for light theme, for dark there is another set of colours.
now we just need to create a theme out of these values, and tell material UI when to use what.
don’t worry if things don’t make much sense, follow along:
create a file called blue.ts
in src/theme/presets/blue.ts
add the following code in it and follow along the comments to know what’s done: (If you’re seeing typescript errors, don’t worry we shall get rid of them soon)
Once this is done, I want you to create 3 more similar files namely red.ts
, green.ts
, default,ts
in the same directory as blue.ts
I’m pasting theme presets for red green and default below, just paste them as it is in your files.
Okay this is done, now how do we tell typescript that if I do <Button colour={’upvote’} />
then don’t throw an error? because I’ve supplied the values here in this object? also we haven’t added proper types to our current theme files. lets create some types.
create a file called index.ts
at src/theme/index.ts
add the following code and read along:
small change before we move forward:
in ALL the four files blue.ts
red.ts
green.ts
default.ts
make the following change:
\import this newly created AppTheme type (add this entire line at the top of the file):
import { AppTheme } from "..";
use it to add explicit typing to our theme object (add ‘: AppTheme’ in front of ‘theme’):
export const theme: AppTheme = {
That’s it!
if you feel confused about anything, checkout blue.ts source here: https://github.com/facinick/MuiTheming/blob/master/src/theme/presets/blue.ts
if your code looks the same, move ahead.
Let’s go back to our Theme provider and get them themes!
Following is the file src/theme/ThemeProvider.tsx
after new changes, follow the comments in the code below:
We are 99% done, let’s move to the final part of the tutorial:
What’s left?
we have created bunch of themes.
we have a context that provides two functions to change theme and modes.
we are picking out the correct theme and supplying it to MUI provider.
we still need to pick the theme and apply it to our components!
Open src/App.tsx
and add the following code
when you supply colour={’primary’}
to a button, it’ll automatically pick background and text colour from theme
but in case of let’s say Box, you’ll have to specify background and font colour as we are doing above.
generally, like the name suggests,
use primary colours for important UI elements that will draw user attention
use secondary colours for not so important ui elements
use container colours for well container elements like cards, boxes, paper etc.
again, primary containers are important UI containers and primary container contrastText is the text to be shown on it