About CSS Variables in Themes

5 Apr 202524 minutes to read

CSS variables, or custom properties, are entities defined by CSS authors that hold specific values applicable throughout a CSS file. They are named with two hyphens (–) followed by an identifier. These variables can take any valid CSS value including colors, lengths, or fonts. To access the value of a CSS variable, use the var() function.

Syncfusion® provides modern, highly customizable themes using CSS variables. These themes deliver a consistent, visually appealing appearance across Syncfusion® components. Available themes include:

  • Material 3 Theme
  • Fluent 2 Theme
  • Bootstrap 5.3 Theme
  • Tailwind 3.4 Theme

CSS Themes - Syncfusion® Angular Controls

The Material 3, Fluent 2, Bootstrap 5.3, and Tailwind 3.4 themes have been integrated into all EJ2 Controls, featuring light and dark variants. These themes use CSS variables, simplifying control color customization within CSS. You can effortlessly switch between light and dark modes, accommodating user preferences and application necessities.

Note: In the Material 3 theme, color CSS variables are defined with rgb() values. Using hex values might cause improper functionality. For instance, earlier versions of Material used $primary: #6200ee;. Now in Material 3, it’s –color-sf-primary: 98, 0, 238;.

Using CSS Variables in Modern Themes

Modern themes enable easy control color changes using CSS variables. Each theme has unique variable settings, so it’s crucial to follow specific instructions per theme to maintain consistent, efficient styling across your application.

Below are examples of defining CSS variables in these themes:

/* rgb() values of material3 theme */
:root {
    --color-sf-black: 0, 0, 0;
    --color-sf-white: 255, 255, 255;
    --color-sf-primary: 103, 80, 164;
    --color-sf-primary-container: 234, 221, 255;
    --color-sf-secondary: 98, 91, 113;
    --color-sf-secondary-container: 232, 222, 248;
    --color-sf-tertiary: 125, 82, 96;
    --color-sf-tertiary-container: 255, 216, 228;
    --color-sf-surface: 255, 255, 255;
    --color-sf-surface-variant: 231, 224, 236;
    --color-sf-background: var(--color-sf-surface);
    --color-sf-on-primary: 255, 255, 255;
    --color-sf-on-primary-container: 33, 0, 94;
    --color-sf-on-secondary: 255, 255, 255;
    --color-sf-on-secondary-container: 30, 25, 43;
    --color-sf-on-tertiary: 255, 255, 255;
  }
/* Hex values of fluent2 theme */
:root {
    --color-sf-black: #000;
    --color-sf-white: #fff;
    --color-sf-primary: #0f6cbd;
    --color-sf-primary-text-color: #fff;
    --color-sf-primary-light: #b4d6fa;
    --color-sf-primary-lighter: #ebf3fc;
    --color-sf-primary-dark: #0f548c;
    --color-sf-primary-darker: #0c3b5e;
    --color-sf-success: #0e700e;
    --color-sf-info: #008aa9;
    --color-sf-warning: #bc4b09;
    --color-sf-danger: #d13438;
    --color-sf-success-light: #54b054;
    --color-sf-info-light: #56bfd7;
    --color-sf-warning-light: #fee5d7;
    --color-sf-danger-light: #eeacb2;
    --color-sf-success-dark: #54b054;
    --color-sf-info-dark: #56bfd7;
    --color-sf-warning-dark: #8a3707;
    --color-sf-danger-dark: #6e0811;
  }
:root {
    --color-sf-black: 0, 0, 0;
    --color-sf-white: 255, 255, 255;
    --color-sf-content-bg-color: #fff;
    --color-sf-content-bg-color-alt1: #f8f9fa;
    --color-sf-content-bg-color-alt2: #e9ecef;
    --color-sf-content-bg-color-alt3: #dee2e6;
    --color-sf-content-bg-color-alt4: #ced4da;
    --color-sf-content-bg-color-alt5: #adb5bd;
    --color-sf-content-bg-color-hover: #f8f9fa;
    --color-sf-content-bg-color-pressed: #e9ecef;
    --color-sf-content-bg-color-focus: #e9ecef;
    --color-sf-content-bg-color-selected: #0d6efd;
    --color-sf-content-bg-color-dragged: #ced4da;
    --color-sf-content-bg-color-disabled: #e9ecef;
    --color-sf-flyout-bg-color: #fff;
    --color-sf-flyout-bg-color-hover: #f8f9fa;
    --color-sf-flyout-bg-color-pressed: #0d6efd;
    --color-sf-flyout-bg-color-focus: #f8f9fa;
    --color-sf-overlay-bg-color: 0, 0, 0;
    --color-sf-table-bg-color-hover: rgba(0, 0, 0, .07);
}
:root{
  --color-sf-content-bg-color: rgba(255, 255, 255);
  --color-sf-content-bg-color-alt1: #f9fafb;
  --color-sf-content-bg-color-alt2: #f3f4f6;
  --color-sf-content-bg-color-alt3: #e5e7eb;
  --color-sf-content-bg-color-alt4: #9ca3af;
  --color-sf-content-bg-color-alt5: #6b7280;
  --color-sf-content-bg-color-hover: #f9fafb;
  --color-sf-content-bg-color-pressed: #f3f4f6;
  --color-sf-content-bg-color-focus: #f9fafb;
  --color-sf-content-bg-color-selected: #e5e7eb;
  --color-sf-content-bg-color-dragged: #f3f4f6;
  --color-sf-content-bg-color-disabled: #ffffff;
  --color-sf-flyout-bg-color: #ffffff;
  --color-sf-flyout-bg-color-hover: #f3f4f6;
  --color-sf-flyout-bg-color-pressed: #e5e7eb;
  --color-sf-flyout-bg-color-focus: #f3f4f6;
  --color-sf-flyout-bg-color-selected: #e5e7eb;
  --color-sf-flyout-bg-color-disabled: #fff;
  --color-sf-overlay-bg-color: rgba(107, 114, 128, 74.9);
  --color-sf-table-bg-color-hover: #f9fafb;
  --color-sf-table-bg-color-pressed: #f3f4f6;
  --color-sf-table-bg-color-selected: #e5e7eb;
  --color-sf-text-input-bg-color: #ffffff;
  --color-sf-treeview-item-active-hover-bg: #e5e7eb;
}

Obtaining these Themes

Syncfusion® offers themes via two main methods:

  • Package
  • CDN links

Theme Color Customization

CSS variables enable real-time dynamic color changes using JavaScript, supporting interactive designs that respond to user actions or dynamic factors.

CSS-Based Customization

Below is an example of Material 3 customization using CSS classes.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { ButtonModule } from '@syncfusion/ej2-angular-buttons'
import { enableRipple } from '@syncfusion/ej2-base'
import { FormsModule } from '@angular/forms'

import { Component } from '@angular/core';

@Component({
imports: [
        
        ButtonModule,
        FormsModule
    ],


standalone: true,
    selector: 'app-root',
    styleUrls:['./styles.css'],
    template:`<div>   
     <!-- Primary Button - Used to represent a primary action. -->
     <button ejs-button cssClass="e-primary">Button</button>
     </div>`  
})

export class AppComponent { 
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Default Material 3 Primary Value

default primary value

Customized Material 3 Primary Value

customized primary value

Example of Fluent 2 customization using CSS classes.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { ButtonModule } from '@syncfusion/ej2-angular-buttons'
import { enableRipple } from '@syncfusion/ej2-base'
import { FormsModule } from '@angular/forms'

import { Component } from '@angular/core';

@Component({
imports: [
        
        ButtonModule,
        FormsModule
    ],


standalone: true,
    selector: 'app-root',
    styleUrls:['./styles.css'],
    template:`<div>   
     <!-- Primary Button - Used to represent a primary action. -->
     <button ejs-button cssClass="e-primary">Button</button>
     </div>`  
})

export class AppComponent { 
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Default Fluent 2 Primary Value

default primary value

Customized Fluent 2 Primary Value

customized primary value

Example of Bootstrap 5.3 customization using CSS classes.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { ButtonModule } from '@syncfusion/ej2-angular-buttons'
import { enableRipple } from '@syncfusion/ej2-base'
import { FormsModule } from '@angular/forms'
import { Component } from '@angular/core';

@Component({
imports: [ 
        ButtonModule,
        FormsModule
    ],
    standalone: true,
    selector: 'app-root',
    styleUrls:['./styles.css'],
    template:`<div>   
     <!-- Primary Button - Used to represent a primary action. -->
     <button ejs-button cssClass="e-primary">Button</button>
     </div>`  
})

export class AppComponent { 
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Default Bootstrap 5.3 Primary Value

default primary value

Customized Bootstrap 5.3 Primary Value

customized primary value

Example of Tailwind 3.4 customization using CSS classes.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { ButtonModule } from '@syncfusion/ej2-angular-buttons'
import { enableRipple } from '@syncfusion/ej2-base'
import { FormsModule } from '@angular/forms'
import { Component } from '@angular/core';

@Component({
imports: [ 
        ButtonModule,
        FormsModule
    ],
    standalone: true,
    selector: 'app-root',
    styleUrls:['./styles.css'],
    template:`<div>   
     <!-- Primary Button - Used to represent a primary action. -->
     <button ejs-button cssClass="e-primary">Button</button>
     </div>`  
})

export class AppComponent { 
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Default Tailwind 3.4 Primary Value

default primary value

Customized Tailwind 3.4 Primary Value

customized primary value

Easily customize color variable values for Syncfusion® Angular Components with CSS variables.

Light and Dark Mode Switching with CSS Variables

The modern themes support effortless light/dark mode switching. All themes include separate class variables for light and dark modes within a single file, allowing seamless mode transitions within your application.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { ButtonModule, CheckBoxModule } from '@syncfusion/ej2-angular-buttons'
import { enableRipple } from '@syncfusion/ej2-base'
import { SwitchModule} from '@syncfusion/ej2-angular-buttons'
import { FormsModule } from '@angular/forms'
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';

@Component({
imports: [
        
        ButtonModule,
        CheckBoxModule,
        SwitchModule,
        FormsModule,
        CommonModule
    ],


standalone: true,
    selector: 'app-root',
    styleUrls:['./styles.css'],
    template:`<div [ngClass]="{'e-dark-mode': isChecked, 'dark': isChecked}">
    <ejs-checkbox label="Enable Darkmode" (change)="toggleCheckbox()"></ejs-checkbox><br/>
   
     <!-- Primary Button - Used to represent a primary action. -->
     <button ejs-button cssClass="e-primary">Button</button>
   
     <!-- Success Button - Used to represent a positive action. -->
     <button ejs-button cssClass="e-success">Button</button>
   
     <!-- Info Button - Used to represent an informative action -->
     <button ejs-button cssClass="e-info">Button</button>
   
     <!-- Warning Button - Used to represent an action with caution. -->
     <button ejs-button cssClass="e-warning">Button</button>
   
     <!-- Danger Button - Used to represent a negative action. -->
     <button ejs-button cssClass="e-danger">Button</button>
     </div>`  
})

export class AppComponent { 
  public className:string="";
  public checked:boolean=true;

  public isChecked = false;

  toggleCheckbox() {
    this.isChecked = !this.isChecked;
    if (this.isChecked) {
      document.body.classList.add('dark');
    }
    else{
      document.body.classList.remove('dark');
    } 
  }
  
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Mode Switching in Fluent 2 Theme

Fluent 2 also supports both Light and Dark variants. It contains separate class variables for each mode, exemplified in the preview below.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { ButtonModule, CheckBoxModule } from '@syncfusion/ej2-angular-buttons'
import { enableRipple } from '@syncfusion/ej2-base'
import { SwitchModule} from '@syncfusion/ej2-angular-buttons'
import { FormsModule } from '@angular/forms'
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';

@Component({
imports: [
        
        ButtonModule,
        CheckBoxModule,
        SwitchModule,
        FormsModule,
        CommonModule
    ],


standalone: true,
    selector: 'app-root',
    styleUrls:['./styles.css'],
    template:`<div [ngClass]="{'e-dark-mode': isChecked, 'dark': isChecked}">
    <ejs-checkbox label="Enable Darkmode" (change)="toggleCheckbox()"></ejs-checkbox><br/>
   
     <!-- Primary Button - Used to represent a primary action. -->
     <button ejs-button cssClass="e-primary">Button</button>
   
     <!-- Success Button - Used to represent a positive action. -->
     <button ejs-button cssClass="e-success">Button</button>
   
     <!-- Info Button - Used to represent an informative action -->
     <button ejs-button cssClass="e-info">Button</button>
   
     <!-- Warning Button - Used to represent an action with caution. -->
     <button ejs-button cssClass="e-warning">Button</button>
   
     <!-- Danger Button - Used to represent a negative action. -->
     <button ejs-button cssClass="e-danger">Button</button>
     </div>`  
})

export class AppComponent { 
  public className:string="";
  public checked:boolean=true;

  public isChecked = false;

  toggleCheckbox() {
    this.isChecked = !this.isChecked;
    if (this.isChecked) {
      document.body.classList.add('dark');
    }
    else{
      document.body.classList.remove('dark');
    } 
  }
  
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Mode Switching in Bootstrap 5.3 Theme

Bootstrap 5.3 supports both Light and Dark variants through distinct class variables for each mode, as displayed below.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { ButtonModule, CheckBoxModule } from '@syncfusion/ej2-angular-buttons'
import { enableRipple } from '@syncfusion/ej2-base'
import { SwitchModule} from '@syncfusion/ej2-angular-buttons'
import { FormsModule } from '@angular/forms'
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';

@Component({
imports: [
        
        ButtonModule,
        CheckBoxModule,
        SwitchModule,
        FormsModule,
        CommonModule
    ],


standalone: true,
    selector: 'app-root',
    styleUrls:['./styles.css'],
    template:`<div [ngClass]="{'e-dark-mode': isChecked, 'dark': isChecked}">
    <ejs-checkbox label="Enable Darkmode" (change)="toggleCheckbox()"></ejs-checkbox><br/>
   
     <!-- Primary Button - Used to represent a primary action. -->
     <button ejs-button cssClass="e-primary">Button</button>
   
     <!-- Success Button - Used to represent a positive action. -->
     <button ejs-button cssClass="e-success">Button</button>
   
     <!-- Info Button - Used to represent an informative action -->
     <button ejs-button cssClass="e-info">Button</button>
   
     <!-- Warning Button - Used to represent an action with caution. -->
     <button ejs-button cssClass="e-warning">Button</button>
   
     <!-- Danger Button - Used to represent a negative action. -->
     <button ejs-button cssClass="e-danger">Button</button>
     </div>`  
})

export class AppComponent { 
  public className:string="";
  public checked:boolean=true;

  public isChecked = false;

  toggleCheckbox() {
    this.isChecked = !this.isChecked;
    if (this.isChecked) {
      document.body.classList.add('dark');
    }
    else{
      document.body.classList.remove('dark');
    } 
  }
  
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Mode Switching in Tailwind 3.4 Theme

Tailwind 3.4 supports Light and Dark variants with distinct class variables per mode, illustrated in the preview below.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { ButtonModule, CheckBoxModule } from '@syncfusion/ej2-angular-buttons'
import { enableRipple } from '@syncfusion/ej2-base'
import { SwitchModule} from '@syncfusion/ej2-angular-buttons'
import { FormsModule } from '@angular/forms'
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';

@Component({
imports: [
        
        ButtonModule,
        CheckBoxModule,
        SwitchModule,
        FormsModule,
        CommonModule
    ],


standalone: true,
    selector: 'app-root',
    styleUrls:['./styles.css'],
    template:`<div [ngClass]="{'e-dark-mode': isChecked, 'dark': isChecked}">
    <ejs-checkbox label="Enable Darkmode" (change)="toggleCheckbox()"></ejs-checkbox><br/>
   
     <!-- Primary Button - Used to represent a primary action. -->
     <button ejs-button cssClass="e-primary">Button</button>
   
     <!-- Success Button - Used to represent a positive action. -->
     <button ejs-button cssClass="e-success">Button</button>
   
     <!-- Info Button - Used to represent an informative action -->
     <button ejs-button cssClass="e-info">Button</button>
   
     <!-- Warning Button - Used to represent an action with caution. -->
     <button ejs-button cssClass="e-warning">Button</button>
   
     <!-- Danger Button - Used to represent a negative action. -->
     <button ejs-button cssClass="e-danger">Button</button>
     </div>`  
})

export class AppComponent { 
  public className:string="";
  public checked:boolean=true;

  public isChecked = false;

  toggleCheckbox() {
    this.isChecked = !this.isChecked;
    if (this.isChecked) {
      document.body.classList.add('dark');
    }
    else{
      document.body.classList.remove('dark');
    } 
  }
  
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Activating Dark Mode

To enable dark mode, simply add the e-dark-mode class to your application’s body for Material 3, Fluent 2, Bootstrap 5.3, and Tailwind 3.4 themes. This enables seamless dark mode activation. Refer to the example images for guidance.

Material 3 Dark Mode

dark mode

Fluent 2 Dark Mode

dark mode

Bootstrap 5.3 Dark Mode

dark mode

Tailwind 3.4 Dark Mode

dark mode

ThemeStudio Application

The ThemeStudio application now offers integration with the Material 3, Fluent 2, and Bootstrap 5.3 themes, creating a comprehensive solution for theme customization. This enhancement enables effortless theme customization and personalization.

Access the Syncfusion® ThemeStudio application with our themes via this link: Link to Syncfusion® ThemeStudio