Skip to content

Update example with new API #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
264 changes: 144 additions & 120 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,168 +1,192 @@
<!-- default badges list -->
![](https://img.shields.io/endpoint?url=https://codecentral.devexpress.com/api/v1/VersionRange/227836631/25.1.3%2B)
[![](https://img.shields.io/badge/Open_in_DevExpress_Support_Center-FF7200?style=flat-square&logo=DevExpress&logoColor=white)](https://supportcenter.devexpress.com/ticket/details/T845557)
[![](https://img.shields.io/badge/📖_How_to_use_DevExpress_Examples-e9f6fc?style=flat-square)](https://docs.devexpress.com/GeneralInformation/403183)
[![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives)
<!-- default badges end -->
# How to implement a Theme Switcher in Blazor applications
# Implement a Theme Switcher in Blazor Applications

This example demonstrates how to add a Theme Switcher to your application. The switcher in this example is the same as in [DevExpress Blazor Demos](https://demos.devexpress.com/blazor/). It allows users to switch between [DevExpress built-in themes](https://docs.devexpress.com/Blazor/401523/common-concepts/customize-appearance/themes) and external Bootstrap themes (the default theme and [free Bootswatch options](https://bootswatch.com/)).
This example demonstrates how to add a Theme Switcher to your application. Users can switch between DevExpress Fluent and Classic themes and external Bootstrap themes. This example uses the [DxResourceManager.RegisterTheme(ITheme)](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxResourceManager.RegisterTheme(DevExpress.Blazor.ITheme)) method to apply a theme at application startup and the [IThemeChangeService.SetTheme()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService.SetTheme(DevExpress.Blazor.ITheme)) method to change the theme at runtime.


![Blazor - Theme Switcher](images/blazor-theme-switcher.png)

The example's solution targets .NET 8, but you can also integrate this Theme Switcher in projects that target .NET 6 and .NET 7.
## Configure Available Themes

## Add a Theme Switcher to an Application
The theme switcher includes the following themes:

* DevExpress Fluent (Light Blue and Dark Blue)
* DevExpress Classic (Blazing Berry, Blazing Dark, Purple, and Office White)
* [Bootstrap External](https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css)


Create a `Themes.cs` file and configure themes:

Follow the steps below to add a Theme Switcher into your application:

1. Copy this example's [ThemeSwitcher](./CS/switcher/switcher/ThemeSwitcher) folder to your project.
2. In the *_Imports.razor* file, import the `switcher.ThemeSwitcher` namespace and files located in the *ThemeSwitcher* folder:
1. For Classic themes, choose a theme from the built-in DevExpress Blazor [Themes](https://docs.devexpress.com/Blazor/DevExpress.Blazor.Themes) collection:

```cs
@using <YourProjectName>.ThemeSwitcher
@using switcher.ThemeSwitcher
public static readonly ITheme BlazingBerry = Themes.BlazingBerry;
public static readonly ITheme BlazingDark = Themes.BlazingDark;
public static readonly ITheme Purple = Themes.Purple;
public static readonly ITheme OfficeWhite = Themes.OfficeWhite;
```
1. For Fluent themes, call the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method to add theme stylesheets and change theme mode:

3. Copy this example's [switcher-resources](./CS/switcher/switcher/wwwroot/switcher-resources) folder to your application's *wwwroot* folder. The *switcher-resources* folder has the following structure:
```cs
public static readonly ITheme FluentLight = Themes.Fluent.Clone(props => {
props.AddFilePaths("css/theme-fluent.css");
});
public static readonly ITheme FluentDark = Themes.Fluent.Clone(props => {
props.Mode = ThemeMode.Dark;
props.AddFilePaths("css/theme-fluent.css");
});
```
1. For Bootstrap themes, call the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method to add a Bootstrap theme stylesheet. Use the same approach if you want to apply your own stylesheets.

* **css/themes**
Includes nested folders whose names correspond to external Bootstrap themes. Each nested folder stores an external theme's stylesheet (*bootstrap.min.css*). Note that built-in DevExpress themes are added to the application with DevExpress Blazor components and stored separately in the **DevExpress.Blazor.Themes** NuGet package.
```cs
public static readonly ITheme BootstrapDefault = Themes.BootstrapExternal.Clone(props => {
props.Name = "Bootstrap";
props.AddFilePaths("https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css");
props.AddFilePaths("css/theme-bs.css");
});
```
1. Create a list of themes:

* **css/themes.css**
Contains CSS rules used to draw colored squares for each theme in the Theme Switcher.
* **css/theme-switcher.css**
Contains CSS rules that define the Theme Switcher's appearance and behavior.
* **theme-controller.js**
Contains functions that add and remove links to theme stylesheets.
* **theme.svg**
An icon displayed in the Theme Switcher.

4. In the layout file, use the [HttpContextAccessor](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httpcontextaccessor?view=aspnetcore-8.0) class to obtain the current theme from cookies:
```html
@using Microsoft.AspNetCore.Mvc.ViewFeatures
@inject IFileVersionProvider FileVersionProvider
@inject ThemeService Themes
@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
@{
string? InitialThemeName = HttpContextAccessor.HttpContext?.Request.Cookies["ActiveTheme"];
Themes.SetActiveThemeByName(InitialThemeName);
var bsTheme = Themes.GetBootstrapThemeCssUrl(Themes.ActiveTheme);
var dxTheme = Themes.GetThemeCssUrl(Themes.ActiveTheme);
var hlTheme = Themes.GetHighlightJSThemeCssUrl(Themes.ActiveTheme);

string AppendVersion(string path) => FileVersionProvider.AddFileVersionToPath("/", path);

```cs
public enum MyTheme {
Fluent_Light,
Fluent_Dark,

Blazing_Berry,
Blazing_Dark,
Purple,
Office_White,

Bootstrap
}
```
5. In the `head` section of the layout file, replace a link to a theme stylesheet with the following code:
```html
<head>
@if (!string.IsNullOrEmpty(bsTheme)) {
<link rel="stylesheet" href="@AppendVersion(bsTheme)" bs-theme-link />
}
@if (!string.IsNullOrEmpty(dxTheme)) {
<link rel="stylesheet" href="@AppendVersion(dxTheme)" dx-theme-link />
}
@if (!string.IsNullOrEmpty(hlTheme)) {
<link rel="stylesheet" href="@hlTheme" hl-theme-link />
}
</head>
```
6. Register the Theme Switcher's styles in the `head` section of the layout file:
```html
<head>
<link href="switcher-resources/css/theme-switcher.css" rel="stylesheet" />
<link href="switcher-resources/css/themes.css" rel="stylesheet" />
@* ... *@
</head>
```
7. Add the following `div` element to the `body` section of the layout file:
```html
<body>
<div id="switcher-container" data-permanent></div>
@* ... *@
</body>

## Add a Theme Switcher to an Application

Follow the steps below to add a Theme Switcher to your application:

1. Copy this example's [ThemeSwitcher](./CS/switcher/switcher/Components/ThemeSwitcher) folder to your project.

2. Copy the example's [switcher-resources](./CS/switcher/switcher/wwwroot/switcher-resources) folder to your application's *wwwroot* folder. The *switcher-resources* folder has the following structure:

* **js/cookies-manager.js**
Contains a function that stores the theme in a cookie variable.
* **theme-switcher.css**
Contains CSS rules that define the Theme Switcher's appearance and behavior.

3. Add the following services to your application (copy the corresponding files):

* [ThemeService.cs](./CS/switcher/switcher/Services/ThemesService.cs)
Implements [IThemeChangeService](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService) to switch themes at runtime and uses the [SetTheme()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService.SetTheme(DevExpress.Blazor.ITheme)) method to apply the selected theme.
* [Themes.cs](./CS/switcher/switcher/Services/Themes.cs)
Creates a list of themes for the theme switcher using the built-in DevExpres Blazor [Themes](https://docs.devexpress.com/Blazor/DevExpress.Blazor.Themes) collection (for Classic themes) and the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method for Fluent and Bootstrap themes.
* [CookiesService.cs](./CS/switcher/switcher/Services/CookiesService.cs)
Manages cookies.

2. In the [_Imports.razor](./CS/switcher/switcher/Components/_Imports.razor) file, import `{ProjectName}.Components.ThemeSwitcher` and `{ProjectName}.Services` namespaces:

```cs
@using {ProjectName}.Components.ThemeSwitcher
@using {ProjectName}.Services
```
8. Register `Mvc` and `ThemeService` in the `Program.cs` file:

5. Register `ThemesService` and `CookiesService` in the [Program.cs](./CS/switcher/switcher/Program.cs#L13-L16) file. Ensure that this file also contains `Mvc` and `HttpContextAccessor` services:

```cs
builder.Services.AddMvc();
builder.Services.AddScoped<ThemeService>();
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<ThemesService>();
builder.Services.AddTransient<CookiesService>();
```
9. Declare the Theme Switcher component in the *MainLayout.razor* file:
```razor
<ThemeSwitcher />
```
10. *For .NET 6 and .NET 7 applications.* Remove the `@rendermode InteractiveServer` directive from [ThemeSwitcher.razor](./CS/switcher/switcher/ThemeSwitcher/ThemeSwitcher.razor#L2), [ThemeSwitcherContainer.razor](./CS/switcher/switcher/ThemeSwitcher/ThemeSwitcherContainer.razor#L4), and [ThemeSwitcherItem.razor](./CS/switcher/switcher/ThemeSwitcher/ThemeSwitcherItem.razor#L2) files.

## Add Themes to the Theme Switcher
6. Add the following code to the [App.razor](./CS/switcher/switcher/Components/App.razor) file:

Follow the steps below to add an external Bootstrap theme to the Theme Switcher:
* Inject services with the [&#91;Inject&#93; attribute](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.injectattribute):

1. In the **wwwroot/css/themes** folder, create a new folder for this theme. The folder and theme names should match.
```html
@inject IHttpContextAccessor HttpContextAccessor
@inject ThemesService ThemesService
```

* Add script and stylesheet links to the file's `<head>` section and call the [DxResourceManager.RegisterTheme(ITheme)](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxResourceManager.RegisterTheme(DevExpress.Blazor.ITheme)) method to apply a theme on application startup:

2. Add the theme's stylesheet (*bootstrap.min.css*) to the newly created folder.
```html
<head>
@* ... *@
<script src=@AppendVersion("switcher-resources/js/cookies-manager.js")></script>
<link href=@AppendVersion("switcher-resources/theme-switcher.css") rel="stylesheet" />

3. Add the following CSS rule to the *wwwroot/css/themes.css* file:
@DxResourceManager.RegisterTheme(InitialTheme)
@* ... *@
</head>
```

```css
.blazor-themes a.<your-theme-name>:before {
background: <theme-main-color>;
}
```
* Obtain the theme from cookies during component initialization:

4. In *ThemeService.cs*, add the theme name to the **Bootstrap Themes** theme set:
```razor
@code {
private ITheme InitialTheme;
protected override void OnInitialized() {
InitialTheme = ThemesService.GetThemeFromCookies(HttpContextAccessor);
}
}
```

7. Declare the Theme Switcher component in the [MainLayout.razor](./CS/switcher/switcher/Components/Layout/MainLayout.razor#L22) file:

```cs
private static List<ThemeSet> CreateSets(ThemeService config) {
return new List<ThemeSet>() {
new ThemeSet("DevExpress Themes", NEW_BLAZOR_THEMES),
new ThemeSet("Bootstrap Themes", "<your-theme-name>", "default", "default-dark", "cerulean")
};
}
```
```razor
<Drawer>
@* ... *@
<ThemeSwitcher />
@* ... *@
</Drawer>
```

## Remove Themes from the Theme Switcher
## Add Stylesheets to a Theme (Apply Styles to Non-DevExpress UI Elements)

Follow the steps below to remove a built-in DevExpress or external Bootstrap theme from the Theme Switcher:

1. Open *ThemeService.cs* and remove the theme name from the **DevExpress Themes** or **Bootstrap Themes** theme set:
Our DevExpress Blazor themes affect DevExpress components only. To apply theme-specific styles to non-DevExpress elements or the entire application, add external stylesheets to the theme using its `AddFilePaths()` method:

```cs
private static List<ThemeSet> CreateSets(ThemeService config) {
return new List<ThemeSet>() {
new ThemeSet("DevExpress Themes", NEW_BLAZOR_THEMES),
new ThemeSet("Bootstrap Themes", /*"<your-theme-name>"*/, "default", "default-dark", "cerulean")
};
}
```

2. Remove the CSS rule that corresponds to this theme from the *wwwroot/css/themes.css* file.
> Bootstrap themes require external theme-specific stylesheets. Once you register a Bootstrap theme, call the `Clone()` method and add the stylesheet using theme properties.

```css
/* .blazor-themes a.<your-theme-name>:before {
background: <theme-main-color>;
}*/
```

3. *For an external Bootstrap theme.* Delete the *wwwroot/css/themes/\<your-theme-name\>* folder.
```cs
public static readonly ITheme BootstrapDefault = Themes.BootstrapExternal.Clone(props => {
props.Name = "Bootstrap";
// Links a Bootstrap theme stylesheet
props.AddFilePaths("https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css");
// Links a custom stylesheet
props.AddFilePaths("css/theme-bs.css");
});
```

## Change Bootstrap Theme Color Modes

If you want to use dark Bootstrap themes, implement custom logic that applies a `data-bs-theme` attribute to the root <html> element:

* `data-bs-theme="light"` for light themes
* `data-bs-theme="dark"` for dark themes

Refer to the following article for more information: [Color Modes](https://getbootstrap.com/docs/5.3/customize/color-modes/).

## Files to Review

* [ThemeSwitcher](./CS/switcher/switcher/ThemeSwitcher) (folder)
* [ThemeSwitcher](./CS/switcher/switcher/Components/ThemeSwitcher) (folder)
* [switcher-resources](./CS/switcher/switcher/wwwroot/switcher-resources) (folder)
* [App.razor](./CS/switcher/switcher/App.razor)
* [MainLayout.razor](./CS/switcher/switcher/Layout/MainLayout.razor)
* [Services](./CS/switcher/switcher/Services) (folder)
* [App.razor](./CS/switcher/switcher/Components/App.razor)
* [MainLayout.razor](./CS/switcher/switcher/Components/Layout/MainLayout.razor)
* [Program.cs](./CS/switcher/switcher/Program.cs)

## Documentation

* [Themes](https://docs.devexpress.com/Blazor/401523/common-concepts/themes)
<!-- feedback -->
## Does this example address your development requirements/objectives?

[<img src="https://www.devexpress.com/support/examples/i/yes-button.svg"/>](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=blazor-theme-switcher&~~~was_helpful=yes) [<img src="https://www.devexpress.com/support/examples/i/no-button.svg"/>](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=blazor-theme-switcher&~~~was_helpful=no)

## Does this example address your development requirements/objectives?
[<img src="https://www.devexpress.com/support/examples/i/yes-button.svg"/>](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=blazor-theme-switcher&~~~was_helpful=yes) [<img src="https://www.devexpress.com/support/examples/i/no-button.svg"/>](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=blazor-theme-switcher&~~~was_helpful=no)
(you will be redirected to DevExpress.com to submit your response)
<!-- feedback end -->
Binary file modified images/blazor-theme-switcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading