maui-theming

SKILL.md

.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/darkAppThemeBinding markup extension
  • Theme colors in C#SetAppThemeColor(), SetAppTheme<T>()
  • Read OS themeApplication.Current.RequestedTheme
  • Force themeApplication.Current.UserAppTheme = AppTheme.Dark
  • Theme changesRequestedThemeChanged event
  • Custom switching → Swap ResourceDictionary in MergedDictionaries
  • Runtime bindingsDynamicResource (not StaticResource)
Weekly Installs
11
GitHub Stars
71
First Seen
Feb 17, 2026
Installed on
opencode11
github-copilot11
codex11
kimi-cli11
gemini-cli11
amp11