-
Notifications
You must be signed in to change notification settings - Fork 25
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
elenapeskova
merged 9 commits into
DevExpress-Examples:25.1.3+
from
elenapeskova:25.1.3+
Jun 30, 2025
Merged
Changes from 7 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
50ba66d
update image
elenapeskova 2c3e7dd
update image
elenapeskova 9f8c2cb
update readme
elenapeskova 93f35c5
update readme
elenapeskova 72666eb
update readme
elenapeskova 4fb5c04
Apply suggestions from code review
elenapeskova deba282
Apply suggestions from code review
elenapeskova 1fddedf
Apply suggestions from code review
elenapeskova ddaadb8
Apply suggestions from code review
elenapeskova File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,168 +1,185 @@ | ||
<!-- default badges list --> | ||
 | ||
[](https://supportcenter.devexpress.com/ticket/details/T845557) | ||
[](https://docs.devexpress.com/GeneralInformation/403183) | ||
[](#does-this-example-address-your-development-requirementsobjectives) | ||
<!-- default badges end --> | ||
# How to 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/)). | ||
# Implement a Theme Switcher in Blazor Applications | ||
|
||
This example demonstrates how to add a Theme Switcher to your application. Users can switch between DevExpress Fluent and Classic themes and an external Bootstrap theme. 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 themes at runtime. | ||
|
||
elenapeskova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
 | ||
|
||
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/[email protected]/dist/css/bootstrap.min.css) | ||
|
||
|
||
Create a `Themes.cs` file and configure themes as follows: | ||
|
||
elenapeskova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1. For Classic themes, choose a theme from the built-in DevExpress Blazor [Themes](https://docs.devexpress.com/Blazor/DevExpress.Blazor.Themes) collection: | ||
|
||
Follow the steps below to add a Theme Switcher into your application: | ||
```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; | ||
``` | ||
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: | ||
|
||
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: | ||
```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. | ||
|
||
```cs | ||
@using <YourProjectName>.ThemeSwitcher | ||
@using switcher.ThemeSwitcher | ||
public static readonly ITheme BootstrapDefault = Themes.BootstrapExternal.Clone(props => { | ||
props.Name = "Bootstrap"; | ||
props.AddFilePaths("https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"); | ||
props.AddFilePaths("css/theme-bs.css"); | ||
}); | ||
``` | ||
1. Declare an enumeration with themes: | ||
|
||
elenapeskova marked this conversation as resolved.
Show resolved
Hide resolved
elenapeskova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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 enum MyTheme { | ||
Fluent_Light, | ||
Fluent_Dark, | ||
|
||
* **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. | ||
Blazing_Berry, | ||
Blazing_Dark, | ||
Purple, | ||
Office_White, | ||
|
||
* **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); | ||
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: | ||
|
||
elenapeskova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
```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 [[Inject] 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 Specific Stylesheets | ||
|
||
elenapeskova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Follow the steps below to remove a built-in DevExpress or external Bootstrap theme from the Theme Switcher: | ||
Our DevExpress Blazor themes affect DevExpress components only. In case you need to apply theme-specific styles to non-DevExpress elements or the entire application, add external stylesheets to the theme using its `AddFilePaths()` method: | ||
|
||
elenapeskova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1. Open *ThemeService.cs* and remove the theme name from the **DevExpress Themes** or **Bootstrap Themes** theme set: | ||
> Bootstrap themes require external theme-specific stylesheets. Once you register a Bootstrap theme, call the `Clone()` method and add an appropriate stylesheet using theme properties. | ||
|
||
elenapeskova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
```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") | ||
}; | ||
} | ||
``` | ||
```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/[email protected]/dist/css/bootstrap.min.css"); | ||
// Links a custom stylesheet | ||
props.AddFilePaths("css/theme-bs.css"); | ||
}); | ||
``` | ||
|
||
2. Remove the CSS rule that corresponds to this theme from the *wwwroot/css/themes.css* file. | ||
## Change Bootstrap Theme Color Modes | ||
|
||
```css | ||
/* .blazor-themes a.<your-theme-name>:before { | ||
background: <theme-main-color>; | ||
}*/ | ||
``` | ||
If you plan to use dark Bootstrap themes, you need to implement custom logic that applies a `data-bs-theme` attribute to the root <html> element: | ||
* `data-bs-theme="light"` for light themes | ||
elenapeskova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* `data-bs-theme="dark"` for dark themes | ||
elenapeskova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
3. *For an external Bootstrap theme.* Delete the *wwwroot/css/themes/\<your-theme-name\>* folder. | ||
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 --> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.