Skip to main content
Avalonia’s styling system provides a flexible, CSS-like approach to defining the appearance of your application, with built-in support for themes, selectors, and dynamic styling.

Styling Fundamentals

Styles in Avalonia separate appearance from structure, allowing you to define visual properties centrally and apply them consistently.

Style Structure

A style consists of:
  • Selector: Defines which controls the style applies to
  • Setters: Define property values
  • Resources: Reusable values
Basic Style
<Window.Styles>
    <Style Selector="Button">
        <Setter Property="Background" Value="#007ACC" />
        <Setter Property="Foreground" Value="White" />
        <Setter Property="Padding" Value="12,6" />
        <Setter Property="CornerRadius" Value="4" />
    </Style>
</Window.Styles>

<Button Content="Styled Button" />

Styles Class Implementation

Avalonia’s Styles class is a collection that manages style application:
Styles.cs (Simplified from source)
using Avalonia.Collections;
using Avalonia.Styling;

public class Styles : AvaloniaObject,
    IAvaloniaList<IStyle>,
    IStyle,
    IResourceProvider
{
    private readonly AvaloniaList<IStyle> _styles = new();
    private IResourceDictionary? _resources;
    
    // Resource dictionary for this style collection
    public IResourceDictionary Resources
    {
        get => _resources ?? (Resources = new ResourceDictionary());
        set => _resources = value;
    }
    
    // Add styles to collection
    public void Add(IStyle item) => _styles.Add(item);
    
    // Try to find a resource
    public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
    {
        // Check local resources first
        if (_resources != null && _resources.TryGetResource(key, theme, out value))
            return true;
        
        // Then check child styles
        for (var i = Count - 1; i >= 0; --i)
        {
            if (this[i].TryGetResource(key, theme, out value))
                return true;
        }
        
        value = null;
        return false;
    }
}

Selectors

Selectors determine which elements a style applies to, using CSS-like syntax:

Type Selectors

<!-- Applies to all Buttons -->
<Style Selector="Button">
    <Setter Property="Background" Value="Blue" />
</Style>

Pseudo-classes

Style elements based on their state:
Pseudo-class Selectors
<Window.Styles>
    <!-- Normal state -->
    <Style Selector="Button.primary">
        <Setter Property="Background" Value="#007ACC" />
    </Style>
    
    <!-- Hover state -->
    <Style Selector="Button.primary:pointerover">
        <Setter Property="Background" Value="#005A9E" />
    </Style>
    
    <!-- Pressed state -->
    <Style Selector="Button.primary:pressed">
        <Setter Property="Background" Value="#004578" />
    </Style>
    
    <!-- Disabled state -->
    <Style Selector="Button.primary:disabled">
        <Setter Property="Opacity" Value="0.5" />
    </Style>
    
    <!-- Focused state -->
    <Style Selector="TextBox:focus">
        <Setter Property="BorderBrush" Value="#007ACC" />
        <Setter Property="BorderThickness" Value="2" />
    </Style>
</Window.Styles>
Common pseudo-classes: :pointerover, :pressed, :disabled, :focus, :selected, :checked

Descendant and Child Selectors

<!-- Applies to TextBlocks anywhere inside StackPanel -->
<Style Selector="StackPanel TextBlock">
    <Setter Property="Margin" Value="0,4" />
</Style>

<StackPanel>
    <TextBlock Text="Styled" />
    <Border>
        <TextBlock Text="Also styled" />
    </Border>
</StackPanel>

Selector Combinators

Advanced Selectors
<!-- OR selector -->
<Style Selector="Button.primary, Button.secondary">
    <Setter Property="Padding" Value="12,6" />
</Style>

<!-- AND with pseudo-class -->
<Style Selector="Button.primary:pointerover">
    <Setter Property="Background" Value="#005A9E" />
</Style>

<!-- NOT selector -->
<Style Selector="Button:not(.primary)">
    <Setter Property="Background" Value="Gray" />
</Style>

<!-- Nth-child -->
<Style Selector="ListBoxItem:nth-child(2n)">
    <Setter Property="Background" Value="#F0F0F0" />
</Style>

Resources

Resources are reusable values referenced throughout your application:

Resource Types

<Window.Resources>
    <!-- Color resource -->
    <Color x:Key="PrimaryColor">#007ACC</Color>
    
    <!-- Brush resources -->
    <SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource PrimaryColor}" />
    <SolidColorBrush x:Key="AccentBrush" Color="#68217A" />
    
    <!-- Gradient brush -->
    <LinearGradientBrush x:Key="GradientBrush" StartPoint="0%,0%" EndPoint="100%,100%">
        <GradientStop Color="#007ACC" Offset="0" />
        <GradientStop Color="#68217A" Offset="1" />
    </LinearGradientBrush>
</Window.Resources>

<Button Background="{StaticResource PrimaryBrush}" />

StaticResource vs DynamicResource

<!-- Resolved once at load time -->
<Button Background="{StaticResource PrimaryBrush}" />

<!-- Better performance -->
<!-- Use for resources that don't change -->
Use StaticResource for static values (colors, margins) and DynamicResource for theme-aware resources.

Resource Dictionaries

Organize resources in separate files:
<ResourceDictionary xmlns="https://github.com/avaloniaui"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <!-- Light theme colors -->
    <Color x:Key="BackgroundColor">#FFFFFF</Color>
    <Color x:Key="ForegroundColor">#000000</Color>
    <Color x:Key="PrimaryColor">#007ACC</Color>
    
    <SolidColorBrush x:Key="BackgroundBrush" Color="{StaticResource BackgroundColor}" />
    <SolidColorBrush x:Key="ForegroundBrush" Color="{StaticResource ForegroundColor}" />
    <SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource PrimaryColor}" />
</ResourceDictionary>

Theme Support

Avalonia provides built-in light and dark theme support:

Theme Variants

Theme Variants
public class ThemeVariant
{
    public static readonly ThemeVariant Light;
    public static readonly ThemeVariant Dark;
    public static readonly ThemeVariant Default; // System preference
}

Setting Application Theme

App.axaml
<Application xmlns="https://github.com/avaloniaui"
             x:Class="MyApp.App"
             RequestedThemeVariant="Dark">
    <!-- App content -->
</Application>

Theme-Aware Resources

Theme-Specific Resources
<ResourceDictionary>
    <!-- Light theme -->
    <ResourceDictionary.ThemeDictionaries>
        <ResourceDictionary x:Key="Light">
            <SolidColorBrush x:Key="BackgroundBrush">#FFFFFF</SolidColorBrush>
            <SolidColorBrush x:Key="ForegroundBrush">#000000</SolidColorBrush>
        </ResourceDictionary>
        
        <!-- Dark theme -->
        <ResourceDictionary x:Key="Dark">
            <SolidColorBrush x:Key="BackgroundBrush">#1E1E1E</SolidColorBrush>
            <SolidColorBrush x:Key="ForegroundBrush">#FFFFFF</SolidColorBrush>
        </ResourceDictionary>
    </ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>

<!-- Use with DynamicResource -->
<Border Background="{DynamicResource BackgroundBrush}" />

Fluent Theme

Avalonia includes a Fluent Design theme:
Using Fluent Theme
<Application xmlns="https://github.com/avaloniaui"
             xmlns:sty="using:Avalonia.Themes.Fluent"
             x:Class="MyApp.App">
    <Application.Styles>
        <sty:FluentTheme />
    </Application.Styles>
</Application>

Custom Theme

<Styles xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    <!-- Define color palette -->
    <Style>
        <Style.Resources>
            <ResourceDictionary>
                <ResourceDictionary.ThemeDictionaries>
                    <ResourceDictionary x:Key="Light">
                        <Color x:Key="SystemAccentColor">#007ACC</Color>
                        <SolidColorBrush x:Key="SystemAccentBrush" Color="{StaticResource SystemAccentColor}" />
                    </ResourceDictionary>
                    
                    <ResourceDictionary x:Key="Dark">
                        <Color x:Key="SystemAccentColor">#0098FF</Color>
                        <SolidColorBrush x:Key="SystemAccentBrush" Color="{StaticResource SystemAccentColor}" />
                    </ResourceDictionary>
                </ResourceDictionary.ThemeDictionaries>
            </ResourceDictionary>
        </Style.Resources>
    </Style>
    
    <!-- Apply styles -->
    <Style Selector="Button">
        <Setter Property="Background" Value="{DynamicResource SystemAccentBrush}" />
    </Style>
</Styles>

Control Themes

Control themes provide complete visual definitions:
Control Theme
<Styles>
    <ControlTheme x:Key="CustomButtonTheme" TargetType="Button">
        <!-- Default setters -->
        <Setter Property="Background" Value="#007ACC" />
        <Setter Property="Foreground" Value="White" />
        <Setter Property="Padding" Value="12,6" />
        <Setter Property="CornerRadius" Value="4" />
        
        <!-- Template -->
        <Setter Property="Template">
            <ControlTemplate>
                <Border Background="{TemplateBinding Background}"
                        CornerRadius="{TemplateBinding CornerRadius}"
                        Padding="{TemplateBinding Padding}">
                    <ContentPresenter Content="{TemplateBinding Content}" />
                </Border>
            </ControlTemplate>
        </Setter>
        
        <!-- State styles -->
        <Style Selector="^:pointerover">
            <Setter Property="Background" Value="#005A9E" />
        </Style>
        
        <Style Selector="^:pressed">
            <Setter Property="Background" Value="#004578" />
        </Style>
    </ControlTheme>
</Styles>

<!-- Apply theme -->
<Button Theme="{StaticResource CustomButtonTheme}" Content="Themed Button" />

Style Precedence

Styles apply in this order (later wins):
  1. Application styles (App.axaml)
  2. Window/UserControl styles
  3. Parent styles (inherited)
  4. Local styles (on the control)
  5. Inline properties (highest priority)
Style Precedence Example
<!-- Application style -->
<Application.Styles>
    <Style Selector="Button">
        <Setter Property="Background" Value="Blue" />
    </Style>
</Application.Styles>

<!-- Window style (overrides application) -->
<Window.Styles>
    <Style Selector="Button.important">
        <Setter Property="Background" Value="Red" />
    </Style>
</Window.Styles>

<!-- Inline property (highest precedence) -->
<Button Classes="important" Background="Green" />
<!-- This button will be GREEN -->

Animations in Styles

Style Animations
<Style Selector="Button:pointerover">
    <Style.Animations>
        <Animation Duration="0:0:0.2" FillMode="Forward">
            <KeyFrame Cue="0%">
                <Setter Property="Background" Value="#007ACC" />
            </KeyFrame>
            <KeyFrame Cue="100%">
                <Setter Property="Background" Value="#005A9E" />
            </KeyFrame>
        </Animation>
    </Style.Animations>
</Style>

Best Practices

1

Use resource dictionaries

Organize colors, brushes, and styles in separate resource dictionary files.
2

Prefer classes over names

Use class selectors (.primary) instead of name selectors (#SubmitButton) for reusability.
3

Theme-aware resources

Use ThemeDictionaries and DynamicResource for proper light/dark theme support.
4

Keep selectors simple

Avoid overly complex selectors for better performance and maintainability.
5

Test both themes

Always test your app in both light and dark themes.

Build docs developers (and LLMs) love