Skip to main content

Theming

HammerUI's theme, ToolkitTheme, holds a light and a dark palette and applies the one that matches the application's theme variant. Every control takes its colors, sizes and corner radii from theme resources, so a change of mode, accent or palette reaches every control in place, without restarting. This page covers switching modes and accents, replacing palettes, and using the same resources in your own controls.

Modes and accents​

ThemeManager changes the mode and the accent of an application that includes ToolkitTheme. Create it once, after the application has loaded its styles, and keep it:

using HammerUI.Theming;

var theme = new ThemeManager(Application.Current!);
theme.Mode = ThemeMode.System;
theme.Accent = Avalonia.Media.Color.Parse("#5B5BEF");
theme.Changed += (_, _) => Console.WriteLine(theme.ActualVariant);
MemberWhat it does
ModeThemeMode.System follows the operating system, Light and Dark fix the variant. Setting it changes the application's RequestedThemeVariant.
AccentThe accent color of both palettes. Hover, pressed and subtle shades are derived from it.
ActualVariantThe variant in effect, with System resolved to light or dark.
ChangedRaised when the mode, the accent or the variant in effect changes.

ThemeManager implements IThemeManager, so you can pass the interface to code that only switches themes. It listens to the application, so dispose it when the application exits.

A toggle between light and dark, as the gallery's app bar has:

theme.Mode = theme.ActualVariant == ThemeVariant.Dark ? ThemeMode.Light : ThemeMode.Dark;

Palettes​

A ThemePalette is the set of colors one variant uses. ThemePalette.Light and ThemePalette.Dark are the defaults; the default accent is #5B5BEF. To change more than the accent, create a palette with with and give it to the theme:

var toolkit = Application.Current!.Styles.OfType<ToolkitTheme>().First();
toolkit.DarkPalette = ThemePalette.Dark with { Background = Avalonia.Media.Color.Parse("#101114") };

ToolkitTheme.LightPalette and DarkPalette replace one palette, SetPalette(variant, palette) does the same by variant and SetAccent(color) changes the accent of both. The colors a palette sets:

ColorUsed for
Accent, AccentForegroundOnly the focused element, the primary button, the selected item and progress, and the text on them.
BackgroundSurface level 0: the window itself, its toolbars, stripes and status bar.
Surface, SurfaceRaised, SurfaceSunkenSurface level 1, panels and editors; level 2, popups, menus and dialogs; and recessed areas such as fields.
SurfaceHover, SurfacePressedTranslucent overlays for hovered and pressed items.
BorderSubtle, BorderStrongDividers and outlines, and the outlines of inputs.
TextPrimary, TextSecondary, TextMuted, TextDisabledText from most to least prominent.
Success, Warning, Danger, InfoStatus colors for badges, toasts and validation.
ScrimThe dimming behind dialogs.

AccentHover, AccentPressed and AccentSubtle are derived from Accent; Outline, the faint line around popups, from TextPrimary; IsDark tells from the background whether a palette is dark. ColorMath.Mix, WithAlpha and Luminance are the helpers the derivation uses, and you can use them too.

Resource keys​

Every palette color is published as a brush and as a color: AccentBrush and AccentColor, SurfaceBrush and SurfaceColor, and so on for each color above. The three surface levels are also published as Surface0Brush, Surface1Brush and Surface2Brush, and the popup outline as OutlineBrush. The names are constants on ThemeKeys, for code that looks resources up. Reference them with DynamicResource, so your controls follow mode and accent changes:

<Border Background="{DynamicResource SurfaceBrush}" BorderBrush="{DynamicResource BorderSubtleBrush}" BorderThickness="1"
CornerRadius="{DynamicResource CornerRadiusLarge}">
<TextBlock Text="Ready" Foreground="{DynamicResource TextSecondaryBrush}" />
</Border>

In code, bind to the resource rather than reading it once:

text.Bind(TextBlock.ForegroundProperty, text.GetResourceObservable(ThemeKeys.TextSecondaryBrush));

The theme also publishes sizes, fonts and shadows:

KeyValue
CornerRadiusSmall, CornerRadiusMedium, CornerRadiusLarge4, 6 and 8
FontSizeCaption, FontSizeBody, FontSizeSubtitle, FontSizeTitle12, 13, 14 and 20
ControlHeight, RowHeight28, the height of buttons, fields and list rows
ToolbarHeight, StripeWidth40, the height of toolbars and the width of tool stripes
MonoFontFamilyCascadia Mono, JetBrains Mono, Consolas and other monospaced fonts, the first one installed
ShadowRaised, ShadowPopupThe shadows of raised cards and of popups, set per variant

Sizes and spacing follow a 4 px grid. Menus, context menus and flyouts fade in over 120 ms.

Text and surface classes​

The theme styles some plain controls by class, so you rarely set colors on text yourself:

ClassEffect
TextBlock.title, subtitlePage and section titles.
TextBlock.sectionSmall uppercase headings over groups of content.
TextBlock.caption, muted, secondarySmaller or quieter text.
TextBlock.monoMonospaced text, such as values and paths.
Border.cardA raised card with a border and rounded corners.
Border.surface0, surface1, surface2A surface of that level; surface2, also named popup, adds the outline, rounded corners and the popup shadow.
Border.panelA panel surface.
Border.divider-h, divider-vThin horizontal and vertical dividers.
  • Shell styles for the app bar, tool strip and status bar.
  • Controls for the classes each control accepts.