When talking about the theming, we may actually need to talk about two different aspects of it, though they usually come together. There are UI “appearance” settings such as font weight and size, background color, border width, etc. But there are, also, layout templates which are meant to define common application layout, layout elements, and, sometimes, even the behavior of those elements.
In the web development, cascading style sheets pretty much cover “appearance” part, and, as for the layout templates, different frameworks may be doing it differently, but, nonetheless, there is no lack of capabilities.
In the Canvas Apps world, this is s little trickier, it seems.
Let’s talk about the appearance first, and let’s look at the example below:
I just added a button to an empty screen, and that button its properties such as fill color and/or pressed fill color set to the default values.
There is, however, no place where I could say “here is a set of default values I want to use in my app, so please apply those defaults to the UI elements in this app”.
At the first glance, the best we can do there is:
- We could start using variables when initializing control properties
- We can, perhaps, initialize all those “theme” variables in the on start of the application
- And, then, we can probably prepare different sets of initialization code to support different themes
So it would look like this:
This post is, mostly, about the options we have to apply consistent theming to our Canvas Apps.
Actually, before I continue… Canvas Apps have a bunch of predefined themes out of the box:
Once applied, those themes affect default settings of all elements on all screens (unless, of course, those settings have already been update by the app maker).
This might be good enough for a lot of applications to be fair, and the rest might be about tweaking specific settings here and there by applying “variable” approach. However, the initial reason I wanted to get this post out is that there are a couple of other theming options out there which I wanted to look at a bit closer.
There are theming components in the Creator Kit: https://learn.microsoft.com/en-us/power-platform/guidance/creator-kit/theme
And there is a theming solution in the CoE Starter Kit: https://learn.microsoft.com/en-us/power-platform/guidance/coe/setup-theming
Creator Kit is relying on the variables in that sense. Basically, you can define theme object in the onstart of the app, then it gets applied to the individual components which come with the creator kit. And, if you need to apply those same settings to the regular components, you can still access theme properties through the theme object.
There is, also, a Fluent Theme Designer application in the “Creator Kit References” apps solution which we can use to define and generate those theme objects:
Notice that “palette” property on the right, btw. If you are familiar with the Fluent UI (and I am not that familiar at all), this should tell you what those themes are, since, basically, this is all Fluent UI React, it seems:
The main drawback of this approach is that theme properties don’t get applied to the out of the box components just like that, and you have to have your components created in such a way that default values are retrieved from the theme object. Which is how Creator Kit components seem to be doing it, because, well, those are Fluent UI components after all:
There are theme customization options in the CoE starter kit as well, though, and they are also quite powerful. But they are different, too, since, even though they seem to be using a somewhat similar concept, those themes are, actually, getting applied to the out of the box Canvas App components as well.
How does that happen?
If you tried unpacking a save msapp (canvas app) file using “pac” tool:
You might find Themes.json file in the output:
Try unpacking CoE template apps (table or phone), and you’ll get this kind of themes.json file:
Notice how a lot of palette values are defined through variables.
If you scroll down in that file, you’ll see how default properties are set for each control – for example, here is how it’s done for the button control:
Then what’s left is to initialize those variables in the on start of the app, and CoE takes a different approach from the Starter Kit in that sense, since it’s storing theme settings in the Dataverse tables, and, then, those are supposed to be loaded in the OnStart of the app:
Of course nothing is stopping us from just assigning those values in the OnStart (without loading them from Dataverse), but, when they are stored in Dataverse, they might be applied and updated a bit more consistently… in a given environment. The last part of that statement is somewhat unexpected, since, yes, if those settings are stored in the Dataverse, they don’t just get deployed to the other environments as part of the solution, for example. They have to be deployed as “data”.
And, then, there is a caveat here since “pac canvas unpack” is still in the preview.
So where does it leave us?
- There are three different ways to apply theming in Canvas Apps. There are out of the box themes, there are Creator Kit themes, and there are CoE themes
- Out of the box themes are a good starting point, but they don’t seem to be extendable/customizable
- Creator Kit themes work, they are great for the Creator Kit components, but they don’t get applied to the out of the box components automatically
- CoE themes work great for the out of the box components, but Creator Kit won’t recognize them (should not be that difficult to convert into a theme object in the OnStart, though). Also, the concept of storing those themes in the Dataverse tables might be somewhat controversial. And, also, there are potential issues with the tooling being in the public preview still
Would be nice to have one way of doing it, but, perhaps, things will settle / merge eventually ?
However, this seems to be where we need to start talking about the templates, since both CoE and Creator Kit have template / reference apps, and it might be worth creating a template app that sort of combines both approaches. Will see if I can try something for the next post.