Implement Dynamic Theme In Angular

Baskaranajiharan
5 min readFeb 11, 2024

--

What is theme?

Theme refers to a webpage or application's overall visual style and presentation. what is included in the theme

Colors: colors are mostly used in an application to represent background color, font color, button color…etc. nowadays light colors are used in light themes at the same time dark colors are used in dark themes we will come back to this later

Fonts: Fonts are mostly representing to show font size, font style, line height…etc

Layout and Spacing: This includes margin, padding, grid layouts …etc.

Imagery and Icons: The types of images and icons used can set the tone and mood of a theme. It can range from flat, minimalist icons to detailed illustrations and photos.

Create a simple theme

first, we have to create a simple theme

first, I created light & dark themes

Theme path
// Light Theme

$background-color: white;
$primary-color: rgb(248, 245, 245);
$border-color: black;
$font-color: black;

body {
margin: 0;
padding: 0;
height: 100vh;
width: 100vh;
box-sizing: border-box;
}

.container {
background-color: $background-color;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;

.card {
width: 50vw;
height: 50vh;
background-color: $primary-color;
border: 1px solid $border-color;

.header {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}

.title {
color: $font-color;
}
}
}
// Light Theme

$background-color: rgb(36, 35, 35);
$primary-color: rgb(56, 56, 56);
$border-color: rgb(255, 255, 255);
$font-color: rgb(255, 255, 255);

body {
margin: 0;
padding: 0;
height: 100vh;
width: 100vh;
box-sizing: border-box;
}

.container {
background-color: $background-color;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;

.card {
width: 50vw;
height: 50vh;
background-color: $primary-color;
border: 1px solid $border-color;

.header {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}

.title {
color: $font-color;
}
}
}

import light-theme.scss in your style.scss

@import "./themes/light-theme";

Wow! Now our application runs on light mode

if we want to switch just import dark-theme in style.scss file that’s all.

Dynamic Theme allocation

We discussed how to add and change themes, but it’s not the best approach. Each time, we manually remove the light theme and import the dark theme.

In this case, we need to make it dynamic, meaning we have to switch themes dynamically. How is it possible? Let’s discuss this step by step.

In the angular.json file, create two objects with “input”, “bundleName”, and “inject” properties. Here, “input” is the path of your theme file, “bundleName” creates the CSS file in production, and the “inject” property injects CSS files globally

 "styles": [
"src/styles.scss",
{
"input": "./src/themes/light-theme.scss",
"bundleName": "light-theme",
"inject": false
},
{
"input": "./src/themes/dark-theme.scss",
"bundleName": "dark-theme",
"inject": false
}
],

Let’s talk about bundleName & inject property

bundleName: This property gives a name to the generated CSS bundle for this theme. In production builds the SCSS file will be compiled into a separate CSS file with this name

inject: true->(default) In development and production, the CSS file will be automatically injected into the HTML using a <link> tag. This means the styles are immediately available in the document

inject: false-> The CSS file won’t automatically be injected. Instead, you have to manually include the <link> tag with the correct path to the generated CSS file in your HTML or component. This is often used for dynamic theming where the theme might be loaded based on user preferences or other conditions

Let’s create a theme.services.ts file

import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';

@Injectable({
providedIn: 'root',
})
export class ThemeService {
public theme: string = 'light-theme';
constructor(@Inject(DOCUMENT) private document: Document) {}

switchTheme(): void {
let themeLink = this.document.getElementById(
'app-theme'
) as HTMLLinkElement;

if (this.theme === 'light-theme') {
this.theme = 'dark-theme';
themeLink.href = 'dark-theme' + '.css';
return;
}
themeLink.href = 'light-theme' + '.css';
this.theme = 'light-theme';
}
}

and add the default theme(light-theme) in the index.html file

 <link
id="app-theme"
rel="stylesheet"
type="text/css"
href="light-theme.css"
/>

inject the theme service in the component & call the switchTheme Function

import { Component } from '@angular/core';
import { ThemeService } from './theme.service';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent {
buttonLabel: string = 'Dark Mode';
constructor(private themeService: ThemeService) {}

getButtonLabel(): string {
if (this.themeService.theme === 'light-theme') {
return 'Light Mode';
}
return 'Dark Mode';
}
switchTheme(): void {
this.themeService.switchTheme();
}
}

<div class="button-container">
<button (click)="switchTheme()">{{ getButtonLabel() }}</button>
</div>
<div class="container">
<div class="card">
<div class="header">
<p class="title">Welcome</p>
</div>
</div>
</div>
dark-theme figure 1
light-theme figure 2

The “light-theme.css” file is downloaded when the application starts, and the “dark-theme.css

Let’s create a dynamic theme using the Primeng UI library

import priming light-theme in the light-theme.scss file

@import "primeng/resources/themes/md-light-indigo/theme.css";

import priming dark-theme in the dark-theme.scss file

@import "primeng/resources/themes/md-dark-indigo/theme.css";

create a table with a button in that case first import primeng TableModule, ButtonModule

@NgModule({
declarations: [AppComponent, CustomTableComponent],
imports: [BrowserModule, AppRoutingModule, ButtonModule, TableModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}

create a table component to render the table

import { Component, OnInit } from '@angular/core';
import { productData } from './product';
import { ThemeService } from '../theme.service';

@Component({
selector: 'app-custom-table',
templateUrl: './custom-table.component.html',
styleUrls: ['./custom-table.component.scss'],
})
export class CustomTableComponent implements OnInit {
products = productData;

constructor(private themeService: ThemeService) {}

ngOnInit() {}

onThemeChange(): void {
this.themeService.switchTheme();
}
}
<div class="container">
<div class="m-2">
<p-button label="Theme" (click)="onThemeChange()"></p-button>
</div>
<p-table
[value]="products"
[tableStyle]="{ 'min-width': '50rem' }"
styleClass="p-datatable-gridlines p-2"
>
<ng-template pTemplate="header">
<tr>
<th>Code</th>
<th>Name</th>
<th>Category</th>
<th>Quantity</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-product>
<tr>
<td>{{ product.code }}</td>
<td>{{ product.name }}</td>
<td>{{ product.category }}</td>
<td>{{ product.quantity }}</td>
</tr>
</ng-template>
</p-table>
</div>

That’s all. When the theme button is clicked, we can see the application change to the dark theme.

GitHub reference: https://github.com/ajiharan-cerexio/angular-theme

That’s all

Thank you

--

--