Primary APIs:
Styles, Style, ControlTheme, SetterSelectors.*ResourceDictionary, ThemeDictionaries, DynamicResourceStyleInclude, ResourceInclude, merged dictionariesReference docs:
04-styles-themes-resources.md28-custom-themes-xaml-and-code-only.md43-xaml-in-libraries-and-resource-packaging.md49-adaptive-markup-and-dynamic-resource-patterns.mdWeb utility-first systems usually become Avalonia class packs:
u-p-2, u-p-4, u-gap-2u-text-sm, u-text-lg, u-font-semiboldu-bg-surface, u-border-muted<Style Selector="*.u-p-4">
<Setter Property="Padding" Value="16" />
</Style>
<Style Selector="StackPanel.u-gap-2">
<Setter Property="Spacing" Value="8" />
</Style>
Use utility classes sparingly for layout glue; prefer component classes/themes for durable UI systems.
| Web BEM idiom | Avalonia idiom |
|---|---|
.card, .card__title, .card--warning |
control classes (card, card-title, warning) + local styles |
| variant modifiers | separate class selectors or ControlTheme based variants |
Create explicit tokens and keep controls consuming tokens, not literals:
Color + SolidColorBrush<Application.Resources>
<x:Double x:Key="Space.3">12</x:Double>
<x:Double x:Key="Radius.M">10</x:Double>
<SolidColorBrush x:Key="Brush.Surface" Color="#10151E" />
</Application.Resources>
Recommended layering:
primary, danger, success):pointerover, :pressed, :disabled)HTML/CSS utility-heavy markup:
<button class="px-4 py-2 rounded-md bg-blue-600 text-white" disabled>
Save
</button>
.px-4 { padding-inline: 1rem; }
.py-2 { padding-block: .5rem; }
.rounded-md { border-radius: .375rem; }
.bg-blue-600 { background: #2563eb; }
.text-white { color: #fff; }
.bg-blue-600:hover { background: #3b82f6; }
button:disabled { opacity: .5; }
Equivalent Avalonia class strategy:
<Button Classes="u-px-4 u-py-2 u-rounded-m u-bg-primary u-fg-on-primary"
Content="Save" />
<Style Selector="Button.u-bg-primary:pointerover">
<Setter Property="Background" Value="{DynamicResource Brush.PrimaryHover}" />
</Style>
<Style Selector="Button.u-bg-primary:disabled">
<Setter Property="Opacity" Value="0.5" />
</Style>
Migration recommendation:
Start (utility-heavy):
<Button Classes="u-p-3 u-rounded-m u-bg-primary u-text-on-primary" Content="Save" />
Refactor target (theme-centric):
<Button Classes="btn primary" Content="Save" />
<Style Selector="Button.btn">
<Setter Property="Padding" Value="14,9" />
<Setter Property="CornerRadius" Value="{StaticResource Radius.M}" />
</Style>
<Style Selector="Button.btn.primary">
<Setter Property="Background" Value="{DynamicResource Brush.Primary}" />
<Setter Property="Foreground" Value="{DynamicResource Brush.OnPrimary}" />
</Style>
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Styling;
application.Resources["Radius.M"] = new CornerRadius(10);
application.Resources["Brush.Primary"] = new SolidColorBrush(Color.Parse("#2F6FED"));
application.Resources["Brush.OnPrimary"] = Brushes.White;
var baseButton = new Style(x => x.OfType<Button>().Class("btn"))
{
Setters =
{
new Setter(TemplatedControl.PaddingProperty, new Thickness(14, 9)),
new Setter(TemplatedControl.CornerRadiusProperty, application.Resources["Radius.M"])
}
};
var primaryButton = new Style(x => x.OfType<Button>().Class("btn").Class("primary"))
{
Setters =
{
new Setter(TemplatedControl.BackgroundProperty, application.Resources["Brush.Primary"]),
new Setter(TemplatedControl.ForegroundProperty, application.Resources["Brush.OnPrimary"])
}
};
application.Styles.Add(baseButton);
application.Styles.Add(primaryButton);
StyleInclude/ResourceInclude.