maui-theming
.NET MAUI Theming
Two main approaches exist for theming MAUI apps: AppThemeBinding (automatic OS theme response) and ResourceDictionary theming (custom themes with runtime switching). They can be combined.
1. AppThemeBinding (OS Theme Response)
AppThemeBinding is a markup extension that selects a value based on the current system theme.
Properties
| Property | Description |
|---|---|
Light |
Value used when the device is in light mode |
Dark |
Value used when the device is in dark mode |
Default |
Fallback value when the device theme is unknown |
XAML Usage
<Label Text="Themed text"
TextColor="{AppThemeBinding Light=Green, Dark=Red}"
BackgroundColor="{AppThemeBinding Light=White, Dark=Black}" />
<!-- With StaticResource or DynamicResource values -->
<Label TextColor="{AppThemeBinding Light={StaticResource LightPrimary},
Dark={StaticResource DarkPrimary}}" />
C# Extension Methods
var label = new Label();
// Color-specific helper
label.SetAppThemeColor(Label.TextColorProperty, Colors.Green, Colors.Red);
// Generic helper for any type
label.SetAppTheme<Color>(Label.TextColorProperty, Colors.Green, Colors.Red);
2. ResourceDictionary Theming (Custom Themes)
Use separate ResourceDictionary files with matching keys to define themes, then swap them at runtime.
Define Theme Dictionaries
Each ResourceDictionary must have a code-behind file that calls InitializeComponent().
LightTheme.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Themes.LightTheme">
<Color x:Key="PageBackgroundColor">White</Color>
<Color x:Key="PrimaryTextColor">#333333</Color>
<Color x:Key="AccentColor">#2196F3</Color>
</ResourceDictionary>
LightTheme.xaml.cs
namespace MyApp.Themes;
public partial class LightTheme : ResourceDictionary
{
public LightTheme() => InitializeComponent();
}
DarkTheme.xaml.cs — same pattern, different values, same keys.
Consume with DynamicResource
Use DynamicResource (not StaticResource) so values update at runtime when the dictionary changes:
<ContentPage BackgroundColor="{DynamicResource PageBackgroundColor}">
<Label Text="Hello"
TextColor="{DynamicResource PrimaryTextColor}" />
<Button Text="Action"
BackgroundColor="{DynamicResource AccentColor}" />
</ContentPage>
Switch Themes at Runtime
void ApplyTheme(ResourceDictionary theme)
{
var mergedDictionaries = Application.Current!.Resources.MergedDictionaries;
mergedDictionaries.Clear();
mergedDictionaries.Add(theme);
}
// Usage
ApplyTheme(new LightTheme());
ApplyTheme(new DarkTheme());
System Theme Detection
Current Theme
AppTheme currentTheme = Application.Current!.RequestedTheme;
// Returns AppTheme.Light, AppTheme.Dark, or AppTheme.Unspecified
Override the System Theme
// Force a specific theme regardless of OS setting
Application.Current!.UserAppTheme = AppTheme.Dark;
// Reset to follow the system theme
Application.Current!.UserAppTheme = AppTheme.Unspecified;
React to Theme Changes
Application.Current!.RequestedThemeChanged += (s, e) =>
{
AppTheme newTheme = e.RequestedTheme;
// Update UI or switch ResourceDictionaries
};
Combining Both Approaches
Use AppThemeBinding with DynamicResource values for maximum flexibility:
<Label TextColor="{AppThemeBinding
Light={DynamicResource LightPrimary},
Dark={DynamicResource DarkPrimary}}" />
Or react to system changes and swap full ResourceDictionaries:
Application.Current!.RequestedThemeChanged += (s, e) =>
{
ApplyTheme(e.RequestedTheme == AppTheme.Dark
? new DarkTheme()
: new LightTheme());
};
Platform Support & Gotchas
| Platform | Minimum Version |
|---|---|
| iOS | 13+ |
| Android | 10+ (API 29) |
| macOS Catalyst | 10.14+ |
| Windows | 10+ |
Android: ConfigChanges.UiMode
MainActivity must include ConfigChanges.UiMode or theme change events will not fire and the activity may restart instead:
[Activity(Theme = "@style/Maui.SplashTheme",
MainLauncher = true,
ConfigurationChanges = ConfigChanges.ScreenSize
| ConfigChanges.Orientation
| ConfigChanges.UiMode // Required for theme detection
| ConfigChanges.ScreenLayout
| ConfigChanges.SmallestScreenSize
| ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity { }
CSS Theming Limitation
MAUI supports CSS styling, but CSS-based themes cannot be swapped dynamically at runtime. Use ResourceDictionary theming instead for dynamic theme switching.
Quick Reference
- OS light/dark →
AppThemeBindingmarkup extension - Theme colors in C# →
SetAppThemeColor(),SetAppTheme<T>() - Read OS theme →
Application.Current.RequestedTheme - Force theme →
Application.Current.UserAppTheme = AppTheme.Dark - Theme changes →
RequestedThemeChangedevent - Custom switching → Swap
ResourceDictionaryinMergedDictionaries - Runtime bindings →
DynamicResource(notStaticResource)