
Recently, we looked at the newwidget middleware that is available in Dojo. Aside from maintaining widget state or application stores, you can also use thetheme
middleware tostyle your widgets.
Let's take aprevious example that used the function based widgets and add a theme to it.
Themes
Themes are a great way to build applications and widgts that could be used by others. You might build alibrary of widgets to share with others. You can release the widgets with a default generic theme, but also allow others to provide their own themes. This lets developers repurpose widgets and applications for blogs, dashboards, or other applications and let them use a uniform theme.
You could even let users of your application choose their theme, such as providing a dark and light theme.
To add themes to our own applicaun, we can add athemes
folder withdark
andlight
folders to organize our themes. Then we can add aUsers
folder to each one for the themeable widget. To make the css available as themes, we need to create a module to export our themes.
/* src/themes/dark/Users/theme.ts *//* src/themes/light/Users/theme.ts */import*ascssfrom"./Users.m.css";exportdefault{"dojo-function-based-widgets-themeable/Users":css};
To export a theme, you need to export an object with thewidget theme key and the referenced css. Note the format is as follows.
{package-name}/{widget-css-module-name}: {css}
Now, we can update our widget to make it themeable.
Themeable Widget
Here is what the original widget looked like.
// src/widgets/Users/Users.tsx...exportdefaultrender(functionUsers({middleware:{store}}){const{get,path,executor}=store;constusers=get(path("users"));if(!users){executor(fetchUsersProcess)(null);return<em>Loading users...</em>;}return(<divclasses={[css.root]}><h1>Users</h1><ulclasses={[css.list]}>{userList(users)}</ul></div>);});
We can update it with thetheme
middleware.
import{create,tsx}from"@dojo/framework/core/vdom";// theme middlewareimportthemefrom"@dojo/framework/core/middleware/theme";importicachefrom"@dojo/framework/core/middleware/icache";// dojo theme and dojo checkboximportdojoThemefrom"@dojo/themes/dojo";importCheckbox,{Mode}from"@dojo/widgets/checkbox";// base css and themesimport*ascssfrom"./Users.m.css";importdarkfrom"../../themes/dark/theme";importlightfrom"../../themes/light/theme";...// add the theme middleware to the widgetconstrender=create({icache,store,theme});...exportdefaultrender(functionUsers({middleware:{icache,store,theme}}){const{get,path,executor}=store;constusers=get(path("users"));if(!users){executor(fetchUsersProcess)(null);return<em>Loading users...</em>;}constchecked=icache.getOrSet("checked",false);// if no theme set, default to the light themeif(!theme.get()){theme.set(light);}// extract the themed css to useconstthemedCss=theme.classes(css);return(<divclasses={[themedCss.root]}><Checkboxtheme={dojoTheme}mode={Mode.toggle}checked={checked}onChange={()=>{// use checkbox to toggle themeicache.set("checked",!checked);if(!checked){theme.set(dark);}else{theme.set(light);}}}/><h1>Users</h1><ulclasses={[themedCss.list]}>{userList(users,themedCss)}</ul></div>);});
There is a bit going on here. We're adding some new imports.
// theme middlewareimportthemefrom"@dojo/framework/core/middleware/theme";importicachefrom"@dojo/framework/core/middleware/icache";// dojo theme and dojo checkboximportdojoThemefrom"@dojo/themes/dojo";importCheckbox,{Mode}from"@dojo/widgets/checkbox";// base css and themesimport*ascssfrom"./Users.m.css";importdarkfrom"../../themes/dark/theme";importlightfrom"../../themes/light/theme";constrender=create({icache,store,theme});
We're adding thetheme
middleware and theicache
for the Dojo checkbox so that we can toggle themes. Then we import the base css and our light and dark themes. We then provide these as middleware to the function based widget.
Then we need to use them in the widget.
exportdefaultrender(functionUsers({middleware:{icache,store,theme}}){...constchecked=icache.getOrSet("checked",false);// if no theme set, default to the light themeif(!theme.get()){theme.set(light);}// extract the themed css to useconstthemedCss=theme.classes(css);return(<divclasses={[themedCss.root]}><Checkboxtheme={dojoTheme}mode={Mode.toggle}checked={checked}onChange={()=>{// use checkbox to toggle themeicache.set("checked",!checked);if(!checked){theme.set(dark);}else{theme.set(light);}}}/><h1>Users</h1><ulclasses={[themedCss.list]}>{userList(users,themedCss)}</ul></div>);});
We can toggle the theme by usingtheme.set(customTheme)
and then useconst themedCss = theme.classes(css)
to get our themed css classes to apply to the widget. ThisthemedCss
is what we can use to apply our scoped css class names to the widget.
You can see the result below. Use the toggle button to toggle between light and dark theme.
Once you get the pattern down, applying themes to your widgets can be a lot of fun.
If you are looking at providing a light and dark theme in your own applications, you could even use the preference set by users of Mac OS. You could usematchMedia
to detectprefers-color-scheme
.
if(window.matchMedia("(prefers-color-scheme: dark)").matches){theme.set(dark);}
Things to remember
In general, it too me a little bit to really understand themes in Dojo, and I think I've finally got a good grasp on it.
Here are some things to remember.
- Theme class names must match widget default class names.
- The theme will only be applied to class names in the default
css
of your widget, even if they are empty, make sure they match.
- The theme will only be applied to class names in the default
{package-name}/{widget-css-module-name}
- This is thewidget theme key.- This threw me off a bit, thanks to the Dojo team ondiscord for helping me grasp this one!
- Use a
variables.css
to maintaincommon theme properties. - Read thedocumentation.
- It's incredibly well written and contains all the details you need.
Summary
Theming widgets can be a lot of fun, and you can find yourself diving down a rabbit hole of tweaks and css hacking to make some really cool things. Don't forget you can scaffold themes for@dojo/widgets
using@dojo/cli-create-theme
. This will let you pick and choose which widgets you want to apply themes to.
Building themeable widgets also allows you to build more reusable widgets. This way you can drop your widgets into any other applications and quickly provide new themes without putting in a lot of effort to start from scratch!
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse