Implement Dynamic Theme In Angular
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
// 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>
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