Theming Angular with CSS Variables
Theming web applications has always been a challenge. We’ve had variables for our CSS for a while now in CSS languages like LESS and SASS but those were static. Some of us went as far as to dynamically compile our LESS/SASS on the client or *gasp* inline style all our colors.
Now that CSS variables have became main stream we don’t have to worry about any of that anymore! We can have our cake and eat it too! On a side note, this really makes me question the value of these languages these days.
What are CSS variables you ask?
I’ll let MDN explain it: “CSS variables are entities defined by CSS authors that contain specific values to be reused throughout a document.”. That means just like we’ve been doing for years in LESS and SASS we can do these natively. Since we don’t have to compile these, we can make them dynamic too! A simple CSS variables looks like:
Then on a element we can set the color and it and its children will inherit this color.
Pretty simple huh?
CSS Variables In Angular
Angular already has great support for handling CSS. We can piggyback on that same system and use CSS variables without any pain.
This is nice and all but we can really unlock some power with Angular. Let’s dive into building a complete dynamic theming system with scoping for Angular!
Before we do anything, we need to figure out how we name our styles. I think this diagram is pretty fun because, well its kinda true.
Luckily for us the Material Design Team has put together a guideline for this kind of stuff. Even if you don’t use Material design systems this is a pretty baseline.
With this system the ‘category’ is the background and the ‘on category’ is the text color. This translates very nicely and really makes you think about keeping your colors concise at the same time.
Now that we have figured out the hardest part, we can move to the actual code.
First lets map that theme to a TypeScript object that we can TYPE! YES, typed CSS!
Now that we’ve defined our theme, lets setup a Theme module that we can define our services, directive and configuration in. In this setup, we are going to use the
forRoot option in the module definition to provide options to the manager.
If we want to use this, we can include it in our application passing our themes and the active theme name like:
Next, lets hookup our service that will manage getting our active theme, registering new themes and letting us know when themes change.
Now that we have the management of the theme system hooked up, we need to actually use it.
Now to use the theme system, we just need to decorate any element with this directive and it automatically attach our CSS variables from our service to the element and thus its children.
For bonus points, we could include the module at different scopes of our application and scope the application to have different themes in different sections.
Let’s connect all the dots now and see a demo! Click the stackblitz below to checkout it all wired together!