Category / Section
How to change the theme with customizable color values within a Blazor Application?
10 mins read
This section outlines how to implement a dynamic theme changing with customizable color values within a Blazor Application. Here, we have prepared a sample application incorporating the “bootstrap5-dark” and “tailwind-dark” themes.
Please find the following code snippet and sample for reference:
Here, the Syncfusion Dropdown list and ColorPicker components are utilized for switching between themes and updating colors for the theme variables.
Home.razor
@page "/"
<PageTitle>Index</PageTitle>
@inject DynamicTheming.Shared.ThemeGenerator themeHelper
@inject NavigationManager uriHelper
<h1>Dynamic Theming</h1>
<div>
<table>
<tbody>
<tr>
<td>
CHOOSE THEME
</td>
<td>
<SfDropDownList TItem="Theme" TValue="string" @bind-value="themeHelper.currentTheme" DataSource="@Themes" Placeholder="CHOOSE THEME">
<DropDownListEvents TItem="Theme" TValue="string" ValueChange="OnThemeChange"></DropDownListEvents>
<DropDownListFieldSettings Text="Text" Value="Value"></DropDownListFieldSettings>
</SfDropDownList>
</td>
</tr>
<tr>
<td>
Primary color
</td>
<td>
<SfColorPicker @bind-Value="themeVariables.PrimaryColor" Mode="ColorPickerMode.Palette"></SfColorPicker>
</td>
</tr>
<tr>
<td>
Primary font
</td>
<td>
<SfColorPicker @bind-Value="themeVariables.PrimaryFont" Mode="ColorPickerMode.Palette"></SfColorPicker>
</td>
</tr>
<tr>
<td>
Secondary color
</td>
<td>
<SfColorPicker @bind-Value="themeVariables.SecondaryColor" Mode="ColorPickerMode.Palette"></SfColorPicker>
</td>
</tr>
<tr>
<td>
Secondary font
</td>
<td>
<SfColorPicker @bind-Value="themeVariables.SecondaryFont" Mode="ColorPickerMode.Palette"></SfColorPicker>
</td>
</tr>
<tr>
<td>
<SfButton Content="Update theme" OnClick="UpdateTheme"></SfButton>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</div>
<br />
<br />
<SfButton IsPrimary=true>Button</SfButton>
<br />
<br />
<SfCalendar TValue="DateTime"></SfCalendar>
@code {
private List<Theme> Themes = new List<Theme>() {
new Theme(){ Text = "TailWind Dark", Value = "tailwind-dark" },
new Theme(){ Text = "Bootstrap5 Dark", Value = "bootstrap5-dark" },
};
private ThemeVariable themeVariables = new ThemeVariable();
protected override void OnInitialized()
{
string url = uriHelper.Uri;
int index = url.IndexOf("?theme=");
themeHelper.currentTheme = index > -1 ? url.Substring(index + 7) : Themes[0].Value;
themeVariables = themeHelper.GetThemeVariables();
}
public void OnThemeChange(ChangeEventArgs<string, Theme> args)
{
themeVariables = themeHelper.GetThemeVariables();
}
public void UpdateTheme()
{
themeHelper.RefreshTheme(themeVariables);
}
public class Theme
{
public string Value { get; set; }
public string Text { get; set; }
}
}
<style>
th, td {
padding: 15px;
}
</style>
The new color value for the theme variables will be retrieved, compiled, and refreshed to dynamically update the theme.
ThemeGenerator.cs
using DartSassHost;
using DartSassHost.Helpers;
using JavaScriptEngineSwitcher.ChakraCore;
using Microsoft.AspNetCore.Components;
using System.Text.RegularExpressions;
namespace DynamicTheming.Shared
{
public class ThemeGenerator
{
private IHostEnvironment env;
private NavigationManager uriHelper;
public string currentTheme { get; set; }
protected ThemeVariable themeVariables = new ThemeVariable();
private string PrimaryColorVariable = "$primary";
private string PrimaryFontVariable = "$primary-text-color";
private string SecondaryColorVariable = "$secondary";
private string SecondaryBgColorVariable = "$secondary-bg-color";
private string SecondaryFontVariable = "$secondary-text-color";
private string OutputCssFile { get; set; }
public ThemeGenerator(IHostEnvironment hostingEnvironment, NavigationManager navigationManager)
{
env = hostingEnvironment;
uriHelper = navigationManager;
OutputCssFile = env.ContentRootPath + @"\wwwroot\css\custom-theme.css";
}
public ThemeVariable GetThemeVariables()
{
themeVariables.PrimaryColor = GetValue(PrimaryColorVariable);
themeVariables.PrimaryFont = GetValue(PrimaryFontVariable);
themeVariables.SecondaryFont = GetValue(SecondaryFontVariable);
themeVariables.SecondaryColor = GetValue(currentTheme == "tailwind-dark" ? SecondaryBgColorVariable : SecondaryColorVariable);
return themeVariables;
}
public string GetInputScssFile()
{
return env.ContentRootPath + @"\wwwroot\scss\custom-" + currentTheme + ".scss";
}
public string GetValue(string prop)
{
string value = null;
string themeContent = File.ReadAllText(GetInputScssFile());
Match matchedValue = Regex.Match(themeContent, $\\{prop}: (.*) !default;);
if (matchedValue.Groups[1] != null)
{
value = matchedValue.Groups[1].Value.Trim();
}
return value;
}
public void RefreshTheme(ThemeVariable themeVariables)
{
string InputScssFile = GetInputScssFile();
string output = File.ReadAllText(InputScssFile);
output = Regex.Replace(output, $\\{PrimaryColorVariable}:(.*);, $"{PrimaryColorVariable}: {themeVariables.PrimaryColor} !default;");
output = Regex.Replace(output, $\\{PrimaryFontVariable}:(.*);, $"{PrimaryFontVariable}: {themeVariables.PrimaryFont} !default;");
output = Regex.Replace(output, $\\{SecondaryFontVariable}:(.*);, $"{SecondaryFontVariable}: {themeVariables.SecondaryFont} !default;");
string secondaryColor = currentTheme == "tailwind-dark" ? SecondaryBgColorVariable : SecondaryColorVariable;
output = Regex.Replace(output, $\\{secondaryColor}:(.*);, $"{secondaryColor}: {themeVariables.SecondaryColor} !default;");
try
{
using (var sassCompiler = new SassCompiler(new ChakraCoreJsEngineFactory()))
{
CompilationResult result = sassCompiler.Compile(output,false);
if (result.CompiledContent != null)
{
//Write compiled content to output css file.
File.WriteAllText(OutputCssFile, result.CompiledContent);
//Write updated content to input scss file.
File.WriteAllText(InputScssFile, output);
}
}
}
catch (SassCompilerLoadException e)
{
Console.WriteLine("During loading of Sass compiler an error occurred. See details:");
Console.WriteLine();
Console.WriteLine(SassErrorHelpers.GenerateErrorDetails(e));
}
catch (SassCompilationException e)
{
Console.WriteLine("During compilation of SCSS code an error occurred. See details:");
Console.WriteLine();
Console.WriteLine(SassErrorHelpers.GenerateErrorDetails(e));
}
catch (SassException e)
{
Console.WriteLine("During working of Sass compiler an unknown error occurred. See details:");
Console.WriteLine();
Console.WriteLine(SassErrorHelpers.GenerateErrorDetails(e));
}
uriHelper.NavigateTo(uriHelper.BaseUri + "?theme=" + currentTheme, forceLoad: true);
}
}
public class ThemeVariable
{
public string PrimaryColor { get; set; }
public string PrimaryFont { get; set; }
public string SecondaryColor { get; set; }
public string SecondaryFont { get; set; }
}
}