would it be possible to add to the light and dark mode the "system theme setting"?
simply put, the user may have chosen a mode in his personalization setting, thus using that selection would be great and useful. the setting would be in css:
@media (prefers-color-scheme: dark){
body {
background-color: #21242b;
}
}
with only that code, the theme would change once the user selects the dark or light mode for his system.
obviously you can define other than "body" color setups (like color, cards, li,...)
this is just a small suggestion that will add to the user experience without additional burden.
Hi @Fady1956,
This can't be easily done as a built-in because dark and light themes are defined in separate files. We would have to put everything in one file in order for it work just with a CSS selector.
Having said that there are two options to implement what you are after:
Use a helper CSS file or style
This CSS would @import
the required CSS file depending on the CSS media query. It would be included instead of using RadzenTheme
and the `ThemeService.
To implement this solution replace <RadzenTheme />
in your App.razor with this:
<style>
@@import url(@($"_content/Radzen.Blazor/css/material-base.css?v={typeof(Radzen.Colors).Assembly.GetName().Version}")) (prefers-color-scheme: light);
@@import url(@($"_content/Radzen.Blazor/css/material-dark-base.css?v={typeof(Radzen.Colors).Assembly.GetName().Version}")) (prefers-color-scheme: dark);
</style>
This code snippet will import the required CSS file depending on the user system settings. Using @@
is required because Blazor treats @
as a special symbol which needs to be escaped. This ?v={typeof(Radzen.Colors).Assembly.GetName().Version}
implements cache busting and prevents the browser from loading a stale theme file after upgrading Radzen.Blazor.
Pros
- Easier to implement.
Cons
- It overrides
RadzenTheme
andThemeService
which meansRadzenAppearanceToggle
won't work.
Use a "landing" page
This approach involves having a landing page (with route "/") which runs the CSS query with JavaScript interop and if dark mode is requested sets the current theme and then redirects to the app.
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// Use JS interop to run the CSS media query
var darkMode = await JSRuntime.InvokeAsync<bool>("eval", "window.matchMedia('(prefers-color-scheme: dark)').matches");
if (darkMode)
{
// Set the current theme if needed
ThemeService.SetTheme("material-dark");
}
// Redirect to the real start page of the application
NavigationManager.NavigateTo("/index");
}
}
Pros
- Still relies on
ThemeService
which meansRadzenApperanceToggle
would work as expected as well as everything else that could required `ThemeService.
Cons
- Requires a new page and a new empty layout.
I am attaching two apps that implement both approaches.
SystemThemeApp.zip (263.2 KB)
SystemThemeCss.zip (258.7 KB)
As usual, Thank you Korchev for your assistance which is always appreciated.
However, I was thinking of a simpler approach than what you propose so generously.
OK, I want to keep the ThemeService (which is a good thing), but my proposal was that the ThemeService would propose a third option, i.e. Light, Dark & System.
Since Light & Dark are already there, what remains is in case the user selects the third option (System) the ThemeService would only check what is the user selected option and just go on with selecting either one of the existing Light and Dark.
Actually, I am in favor of using the system selected option at first as the prefered user option, then save his selection for future use.
Anyway, if that is not possible, then it is not possible
Again thank you for your cooperation.
We can't have a "System" option as we don't have such a version of the theme. We have light and dark only. The media query is still needed to load the correct CSS file. If RadzenAppearanceToggle does the check you would always see a flicker in the case the "wrong" CSS file is loaded first.
Korchev,
yes I got the limitations, but still, it would have been nice to have that user experience to be available.
I understand your comments perfectly, but one can dream ...
I believe second version of the example does exactly what you are asking for. The user starts with the "system" theme (dark or light) preset.
yes it might do the trick, but it will not switch when the user changes this option from the settings.
so it might do the trick initially, but not afterwards.
Anyway, as I said: it cannot be done, then let us leave it at that.
The second demo does allow the user to change the appearance from RadzenAppearanceToggle - the user can change the theme even after it has been set. Both demos would reflect a system-wide change if the user refreshes their browser. Did you try any of them?
As I have already said before we can support this behavior only if we merge the light and dark CSS files into one. We are reluctant to this for various reasons:
- It is a breaking change if we decide to delete the "dark" version.
- It would almost double the theme size all users have to download as they will always download the light and dark version regardless which version they use.
- If we decide to keep the existing files would be a lot more effort for us to support.
The solutions I have suggested do not have any of those drawbacks.
korchev,
yes I tried your provided solutions.
what I am saying is that if the user change his selection in the system personalization (not through the app) it is not reflected automatically, while what I provided in my css will reflect automatically. try it and you will understand what I am saying. just use a normal html page adding to it my css and see what happens immediately if you switch in the system (doing nothing in the app) the change is immediately effected.
Yes, it will not change "automatically". I have explained at length why we won't implement this feature in my previous reply. Nothing more to add really. Doubling the CSS payload or our support effort isn't worth the trade off.
yes as I already said: I agree with your comment.