Supporting Dark and High Contrast themes
Uno Platform offers fine-grained customization of typography, corner radius, and styling of UI elements to convey a brand identity in your application. However, platforms like iOS, Android, and web browsers also offer a system-wide color mode that users can change. For instance, Windows uses Light mode by default, but many users prefer Dark mode which is intended to be easier on the eyes in low-light conditions. Many platforms also offer a High Contrast mode to make things easier to see.
These themes affect both the Background and Foreground colors to accommodate user preferences. All of the color modes mentioned above are available for use in your app. This guide will detail how to change the system theme setting, make your app receive change notifications for it, and react to those changes at runtime.
Enable dark mode
As in WinUI, the possible values Light, Dark, and HighContrast correspond to a value users can select in the settings of their respective platforms.
High Contrast mode is often available to enable separately, from a dedicated Accessibility page. For the purpose of this documentation, we will assume the user wants to use Dark mode.
Windows PCs can enable Dark mode from Windows Settings. See Change colors in Windows for more information.
React to OS theme changes
When you change the theme mode on your device, the system will send a notification to your app. The colors of UI elements in your app will automatically switch over as long as you do not specify a theme in any of the following places:
AppconstructorApp.xaml- The
RequestedThemeproperty of a parentFrameworkElement
However, your app can still react manually to changes in the theme mode. To do so, you can use the Uno.CommunityToolkit.WinUI.UI NuGet package. This package is not required to change the app color theme, but it contains a ThemeListener class that can be used to listen for OS theme changes. To actually change the app color theme at runtime, you need to install the Uno.Toolkit.WinUI NuGet package which contains a SystemThemeHelper class.
Below is an example of how to use these classes to change the app theme at runtime based on a raised event:
using CommunityToolkit.WinUI.UI.Helpers;
using Uno.Toolkit.UI;
namespace MyApp.UI.Views;
public class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
ThemeListener.Current.ThemeChanged += OnThemeChanged;
}
private void OnThemeChanged(ThemeListener sender)
{
var theme = SystemThemeHelper.IsRootInDarkMode(this.XamlRoot) ? ElementTheme.Light : ElementTheme.Dark;
SystemThemeHelper.SetApplicationTheme(this.XamlRoot, theme);
}
}
Platform support for element-level theming
The application theme and the OS theme (Light, Dark, and High Contrast) are honored on every target: Windows, WebAssembly, Skia-rendered desktop and mobile, and native Android and iOS.
Element-level theming — setting FrameworkElement.RequestedTheme on a sub-tree so that part of the app uses a different theme than the rest — is fully supported on Windows, WebAssembly, and Skia-rendered targets. There, the theme of an element is established as it enters the visual tree (inherited from its logical parent), so content created at runtime — virtualized list/grid items, popup and flyout content on first open, and controls added after load — resolves the correct element theme immediately.
On native Android and iOS targets (the UIKit / Android-view heads), the framework supports the OS and application theme only; per-element RequestedTheme theming of a sub-tree is intentionally out of scope. Content on those targets follows the application/OS theme. If your app relies on theming a sub-tree independently of the rest of the UI, use a Skia-rendered head on mobile.
Change the app theme at runtime
The SystemThemeHelper.SetApplicationTheme method from Uno.Toolkit.UI can also be used to support an in-app toggle for dark mode. For example, you could add a toggle button to your app's settings page that allows the user to switch between light and dark modes. The following code snippet shows how to implement this:
using Uno.Toolkit.UI;
namespace MyApp.UI.Views;
public class SettingsPage : Page
{
public SettingsPage()
{
this.InitializeComponent();
this.Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
this.DarkModeToggle.IsOn = SystemThemeHelper.IsRootInDarkMode(this.XamlRoot);
}
private void OnDarkModeToggleToggled(object sender, RoutedEventArgs e)
{
var theme = DarkModeToggle.IsOn ? ElementTheme.Light : ElementTheme.Dark;
SystemThemeHelper.SetApplicationTheme(this.XamlRoot, theme);
}
}
Change the app theme at startup
Another method to change the app theme is to adjust it immediately upon startup. The following must only be called in the App class constructor.
public App()
{
this.InitializeComponent();
#if HAS_UNO
Uno.UI.ApplicationHelper.RequestedCustomTheme = nameof(ApplicationTheme.Dark);
#else
this.RequestedTheme = ApplicationTheme.Dark;
#endif
}