Skip to content
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
268 changes: 175 additions & 93 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,100 @@
<!-- default badges list -->
![](https://img.shields.io/endpoint?url=https://codecentral.devexpress.com/api/v1/VersionRange/227836631/25.2.2%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 -->
# Implement a Theme Switcher in Blazor Applications
# Switch Themes and Size Modes in Blazor Applications at Runtime

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.

This example adds a theme switcher to your Blazor 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)

This example also implements a size mode combobox that allows users to switch between small, medium, and large [size modes](https://docs.devexpress.com/Blazor/401784/styling-and-themes/size-modes).

![Blazor - Theme and Size Mode Switchers](images/blazor-theme-and-size-mode-switcher.png)

## Add Resources and Services

To switch themes and size modes at runtime, configure your Blazor application as follows:


1. Copy the example [switcher-resources](./CS/switcher/switcher/wwwroot/switcher-resources) folder to your application *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.
* **js/size-manager.js**
Contains a function that assigns selected size mode to the `--global-size` CSS variable.
* **theme-switcher.css**
Contains CSS rules that define theme switcher appearance and behavior.

2. Add the following services to your application (copy the corresponding files from the [Services](./CS/switcher/switcher/Services) folder):

* [ThemesService.cs](./CS/switcher/switcher/Services/ThemesService.cs)
Implements the [IThemeChangeService](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService) interface 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. Supports custom accent colors for Fluent themes.
* [Themes.cs](./CS/switcher/switcher/Services/Themes.cs)
Creates a list of themes for the theme switcher via the built-in DevExpress Blazor [Themes](https://docs.devexpress.com/Blazor/DevExpress.Blazor.Themes) collection and the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method.
* [CookiesService.cs](./CS/switcher/switcher/Services/CookiesService.cs)
Manages cookies.
* [SizeManager.cs](./CS/switcher/switcher/Services/SizeManager.cs) *(Optional)*
Manages application [size mode](https://docs.devexpress.com/Blazor/401784/styling-and-themes/size-modes) (small, medium, or large).

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

```razor
@using {ProjectName}.Components.ThemeSwitcher
@using {ProjectName}.Services
```

4. Register services in the [Program.cs](./CS/switcher/switcher/Program.cs) file:

```cs
builder.Services.AddDevExpressBlazor();
builder.Services.AddMvc();
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<ThemesService>();
builder.Services.AddTransient<CookiesService>();
builder.Services.AddScoped<SizeManager>();
```

## Configure Available Themes

The theme switcher includes the following themes:

* DevExpress Fluent (Light Blue and Dark Blue)
* DevExpress Fluent (Light/Dark with custom accent color support)
* 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](./CS/switcher/switcher/Services/Themes.cs) file and configure themes:

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


1. For Classic themes, choose a theme from the built-in DevExpress Blazor [Themes](https://docs.devexpress.com/Blazor/DevExpress.Blazor.Themes) collection:
1. For Classic themes, choose a theme from the built-in DevExpress Blazor [Themes](https://docs.devexpress.com/Blazor/DevExpress.Blazor.Themes) collection and add custom stylesheets (using the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method):

```cs
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;
public static readonly ITheme BlazingBerry = Themes.BlazingBerry.Clone(props => {
props.AddFilePaths("css/theme-bs.css");
});
public static readonly ITheme BlazingDark = Themes.BlazingDark.Clone(props => {
props.AddFilePaths("css/theme-bs.css");
});
public static readonly ITheme Purple = Themes.Purple.Clone(props => {
props.AddFilePaths("css/theme-bs.css");
});
public static readonly ITheme OfficeWhite = Themes.OfficeWhite.Clone(props => {
props.AddFilePaths("css/theme-bs.css");
});
```
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:

```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");
});
public static ITheme FluentLight(string? accent = null) {
return Themes.Fluent.Clone(props => {
props.Name = "FluentLight" + accent?.PadLeft(8);
props.SetCustomAccentColor(accent);
props.AddFilePaths("css/theme-fluent.css");
});
}
public static ITheme FluentDark(string? accent = null) {
return Themes.Fluent.Clone(props => {
props.Name = "FluentDark" + accent?.PadLeft(8);
props.SetCustomAccentColor(accent);
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.

Expand All @@ -56,62 +110,72 @@ Create a `Themes.cs` file and configure themes:

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

Blazing_Berry,
Blazing_Dark,
BlazingBerry,
BlazingDark,
Purple,
Office_White,
OfficeWhite,

Bootstrap
}
```

## Add a Theme Switcher to an Application
### Use Custom Accent Colors in Fluent Themes

Follow the steps below to add a Theme Switcher to your application:
The theme switcher allows you to apply a Fluent theme with a custom accent color as follows:

1. Copy this example's [ThemeSwitcher](./CS/switcher/switcher/Components/ThemeSwitcher) folder to your project.
* A masked input field used to enter hex color values
* A color picker for visual color selection

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:
The theme is applied automatically when a user selects the color.

* **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.
Review implementation details in the [ThemeSwitcherContainer.razor](./CS/switcher/switcher/Components/ThemeSwitcher/ThemeSwitcherContainer.razor) file.

3. Add the following services to your application (copy the corresponding files):
### Add Custom Stylesheets to the Application (Apply Styles to Non-DevExpress UI Elements)

* [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.
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:

2. In the [_Imports.razor](./CS/switcher/switcher/Components/_Imports.razor) file, import `{ProjectName}.Components.ThemeSwitcher` and `{ProjectName}.Services` namespaces:
> Bootstrap themes require external theme-specific stylesheets. Once you register a Bootstrap theme, call the `Clone()` method and add the stylesheet using theme properties.

```cs
@using {ProjectName}.Components.ThemeSwitcher
@using {ProjectName}.Services
```
```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");
});
```

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:
### Change Bootstrap Theme Color Modes

```cs
builder.Services.AddMvc();
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<ThemesService>();
builder.Services.AddTransient<CookiesService>();
```
If you want to use dark Bootstrap themes, apply 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/).

## Add a Theme Switcher to Your Application

6. Add the following code to the [App.razor](./CS/switcher/switcher/Components/App.razor) file:
Follow the steps below to add a theme switcher to your application:

1. Copy the [ThemeSwitcher](./CS/switcher/switcher/Components/ThemeSwitcher) folder to your project. The folder contains:
* [ThemeSwitcher.razor](./CS/switcher/switcher/Components/ThemeSwitcher/ThemeSwitcher.razor) - The theme switcher button.
* [ThemeSwitcherContainer.razor](./CS/switcher/switcher/Components/ThemeSwitcher/ThemeSwitcherContainer.razor) - The theme selection panel with all available themes.
* [ThemeSwitcherItem.razor](./CS/switcher/switcher/Components/ThemeSwitcher/ThemeSwitcherItem.razor) - An individual theme item.

2. Add the following code to the [Components/App.razor](./CS/switcher/switcher/Components/App.razor) file:

* Inject services with the [&#91;Inject&#93; attribute](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.injectattribute):

```html
```razor
@using Microsoft.AspNetCore.Mvc.ViewFeatures
@using DevExpress.Blazor
@inject IHttpContextAccessor HttpContextAccessor
@inject IFileVersionProvider FileVersionProvider
@inject ThemesService ThemesService
```

Expand All @@ -123,59 +187,73 @@ Follow the steps below to add a Theme Switcher to your application:
<script src=@AppendVersion("switcher-resources/js/cookies-manager.js")></script>
<link href=@AppendVersion("switcher-resources/theme-switcher.css") rel="stylesheet" />

@DxResourceManager.RegisterTheme(InitialTheme)
@* ... *@
@DxResourceManager.RegisterTheme(Theme)

<link href=@AppendVersion("css/site.css") rel="stylesheet" />
<HeadOutlet @rendermode="InteractiveServer" />
</head>
```

* Obtain the theme from cookies during component initialization:

```razor
@code {
private ITheme InitialTheme;
private ITheme Theme;
private string AppendVersion(string path) => FileVersionProvider.AddFileVersionToPath("/", path);

protected override void OnInitialized() {
InitialTheme = ThemesService.GetThemeFromCookies(HttpContextAccessor);
Theme = ThemesService.GetThemeFromCookies(HttpContextAccessor);
}
}
```

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

```razor
<Drawer>
@* ... *@
<ThemeSwitcher />
@* ... *@
</Drawer>
```
<div class="nav-buttons-container">
@* Navigation buttons *@
<div style="margin-left:auto; display:flex">
<ThemeSwitcher />
</div>
</div>
```

## Add Stylesheets to a Theme (Apply Styles to Non-DevExpress UI Elements)
## Add a Size Mode Switcher

To change size modes at runtime, you must:

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:
1. Copy the [SizeChanger.razor](/CS/switcher/switcher/Components/Layout/SizeChanger.razor) file to the [Components/Layout](/CS/switcher/switcher/Components/Layout/) folder. This file creates a size mode menu and injects the [SizeManager](./CS/switcher/switcher/Services/SizeManager.cs) service.

2. Reference the [size-manager.js](./CS/switcher/switcher/wwwroot/switcher-resources/js/size-manager.js) script in the `<head>` section of the [App.razor](./CS/switcher/switcher/Components/App.razor) 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.


```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");
});
```
```html
<head>
@* ... *@
<script src=@AppendVersion("switcher-resources/js/size-manager.js")></script>
@* ... *@
</head>
```

## Change Bootstrap Theme Color Modes
4. Use the `--global-size` CSS variable to define the font size application-wide:

If you want to use dark Bootstrap themes, implement custom logic that applies a `data-bs-theme` attribute to the root <html> element:
```css
html, body {
/* ... */
font-size: var(--global-size);
}
```

* `data-bs-theme="light"` for light themes
* `data-bs-theme="dark"` for dark themes
5. Declare the size mode switcher component in the [MainLayout.razor](./CS/switcher/switcher/Components/Layout/MainLayout.razor) file:

Refer to the following article for more information: [Color Modes](https://getbootstrap.com/docs/5.3/customize/color-modes/).
```razor
<div class="nav-buttons-container">
@* Navigation buttons *@
<div style="margin-left:auto; display:flex">
<SizeChanger />
<ThemeSwitcher />
</div>
</div>
```

## Files to Review

Expand All @@ -189,10 +267,14 @@ Refer to the following article for more information: [Color Modes](https://getbo
## Documentation

* [Themes](https://docs.devexpress.com/Blazor/401523/common-concepts/themes)
* [Fluent Theme Customization (Accent Colors)](https://docs.devexpress.com/Blazor/405530/styling-and-themes/fluent-theme-customization)
* [Size Modes](https://docs.devexpress.com/Blazor/401784/styling-and-themes/size-modes)

<!-- 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 added images/blazor-theme-and-size-mode-switcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed images/blazor-theme-switcher.png
Binary file not shown.
Loading