Apply NavButtonTheme to eliminate hover flash
Details
Apply the pre-defined NavButtonTheme ControlTheme to all nav button classes
(nav-item, nav-item-collapsed, workspace-btn, nav-footer-item, nav-footer-item-collapsed)
via Property="Theme" Style Setter.
The root cause of the hover flash was that nav buttons were still using Avalonia's
FluentTheme Button ControlTheme, which has internal pseudo-class rules:
^:pointerover /template/ ContentPresenter { Background = ButtonBackgroundPointerOver }
These fire instantly with no transition, producing a visible white flash on hover-out as
the ContentPresenter snaps back before any child element can animate out.
NavButtonTheme replaces the entire ControlTheme with a minimal template:
Border (Background=TemplateBinding, CornerRadius=TemplateBinding, Padding=TemplateBinding)
└─ BrushTransition on Background (0.15s)
└─ ContentPresenter (Foreground=TemplateBinding, no pseudo-class overrides)
With this template active, Button.Background is the sole source of the hover background.
Style rules for each nav button class set hover/active directly on Button:
Button.nav-item:pointerover { Background = ThemeNavHoverBrush }
Button.nav-item.active { Background = ThemePrimaryMutedBrush }
The BrushTransition lives inside the ControlTemplate Border, which is the element whose
Background property changes when Button.Background changes via TemplateBinding. This gives
a clean 0.15s fade both on hover-in and hover-out, with no competing layers.
All Border.nav-bg background styles removed (the inner Border elements remain as structural
padding containers but no longer participate in background animation). TextBlock.nav-label
and IconControl Stroke transitions remain unchanged.
Bump to v1.39.6.
Eliminate nav hover flash via Border.nav-bg isolation from FluentTheme (v1.39.5)
Details
Root cause (definitive): Avalonia's FluentTheme Button ControlTheme has internal
pseudo-class styles that directly set ContentPresenter.Background and Foreground
on :pointerover/:pressed with no transition. These override our BrushTransitions
regardless of how we set them on Button or ContentPresenter via class selectors,
because FluentTheme's ControlTheme styles are applied before our class transitions
resolve in the same layout pass. Both hover-IN and hover-OUT snapped instantly,
appearing as a flash in both directions.
Fix: Moved the visual background off the Button entirely into a child
Border.nav-bg element inside each button's content. FluentTheme can only
target /template/ ContentPresenter — it cannot reach a regular child Border.
Border.nav-bg owns the BrushTransition and the hover/active background colors.
Architecture:
- All nav button classes (nav-item, nav-item-collapsed, nav-footer-item,
nav-footer-item-collapsed, workspace-btn) set Padding=0,
HorizontalContentAlignment=Stretch, VerticalContentAlignment=Stretch.
- Each button's content is wrapped in <Border Classes="nav-bg" Padding="..." CornerRadius="...">.
- Button.nav-item Border.nav-bg { Transitions { BrushTransition Background 0.15s } }
- Button.nav-item:pointerover Border.nav-bg { Background = ThemeNavHoverBrush }
- Button.nav-item.active Border.nav-bg { Background = ThemePrimaryMutedBrush }
- All ContentPresenter /template/ overrides removed — no more fighting FluentTheme.
Text color (TextBlock.nav-label + Button.nav-footer-item TextBlock):
- Foreground set directly on TextBlock via class selectors with BrushTransition 0.15s.
- TextBlock style setters win over ContentPresenter inherited Foreground, so
FluentTheme setting ContentPresenter.Foreground to black has zero effect on labels.
- TextBlocks with explicit inline Foreground bindings (ThemeSuccessBrush, etc.)
keep their colors because local values override style setters.
Also: Removed unused UserControl.Resources NavButtonTheme ControlTheme block
(ControlTheme is not settable via Style Setter in Avalonia compiled AXAML).
Fix sidebar nav text going black on hover in FluentTheme light mode (v1.39.4)
Details
Root cause: Avalonia uses FluentTheme as the base. FluentTheme's Button ControlTheme
contains internal pseudo-class styles at the template level:
^:pointerover /template/ ContentPresenter {
Background = ButtonBackgroundPointerOver
Foreground = ButtonForegroundPointerOver
}
These are template-level styles scoped to the ControlTheme, meaning they target
ContentPresenter directly rather than flowing through Button.Foreground. When our
class selectors set Button.Foreground on hover, the TemplateBinding in ContentPresenter
is overridden by the ControlTheme's explicit ContentPresenter setter, which in the
Light theme resolves ButtonForegroundPointerOver to a near-black color. The result:
text turns black on hover regardless of our Foreground setter on the Button.
Fix: Added explicit ContentPresenter Foreground + Background overrides in each nav
button class (nav-item, nav-item-collapsed, nav-footer-item, nav-footer-item-collapsed,
workspace-btn). Class-level ContentPresenter selectors (e.g. Button.nav-item /template/
ContentPresenter) have higher specificity than ControlTheme's ^:pointerover /template/
ContentPresenter, so our selectors correctly win.
To avoid reintroducing the flash: the base ContentPresenter style for each class
now includes a BrushTransition on Background (0.12s, matching the Button's own
BrushTransition). This ensures ContentPresenter.Background and Button.Background
both animate at identical speed — no racing transitions, no flash.
Summary of ContentPresenter overrides added per button class:
- base: Transitions { BrushTransition Background 0.12s } + Foreground (for text-bearing classes)
- :pointerover: Background = ThemeNavHoverBrush + Foreground = ThemeNavTextHoverBrush (where applicable)
- .active: Background = ThemePrimaryMutedBrush + Foreground = ThemeNavTextHoverBrush (where applicable)
Eliminate sidebar hover icon flash by removing ContentPresenter overrides (v1.39.3)
Details
Root cause: Avalonia Button renders its background through a ContentPresenter in
its default template, using TemplateBinding so ContentPresenter.Background mirrors
Button.Background. When an explicit style selector (Button.foo /template/ ContentPresenter)
sets Background directly, it breaks the TemplateBinding and creates a competing
background source. The Button's BrushTransition animates Button.Background smoothly
over 0.12s, but the ContentPresenter override has no transition — it snaps instantly
to the new color. The result is a visible flash as both backgrounds race: the Button
fades smoothly while the ContentPresenter jumps ahead. This showed up as a brief
icon flash on every pointer enter/leave event in the sidebar.
Fix: Removed all eight /template/ ContentPresenter style blocks from NavigationSidebar.axaml.
- Button.workspace-btn:pointerover ContentPresenter (Background)
- Button.workspace-btn:pressed ContentPresenter → converted to Button.pressed direct
- Button.nav-item.active ContentPresenter (Background + Foreground)
- Button.nav-item-collapsed:pointerover ContentPresenter (Background)
- Button.nav-item-collapsed:pressed ContentPresenter → converted to Button.pressed direct
- Button.nav-item-collapsed.active ContentPresenter (Background)
- Button.nav-footer-item:pointerover ContentPresenter (Background + Foreground)
- Button.nav-footer-item-collapsed:pointerover ContentPresenter (Background)
With these removed, Button.Background is the sole background source. The TemplateBinding
in Avalonia's default Button template reflects it correctly, and the BrushTransition
defined on each button class animates it smoothly through all state changes — hover,
active, pressed — without any competing instant snap from the ContentPresenter.
Fix IconControl theme-aware icon color inheritance (v1.39.2)
Details
Previously, IconControl (which extends Control directly) had no Foreground
property and no inheritance mechanism. When the explicit Stroke style selector
could not apply (e.g., context menus, collapsed sidebar, or any icon not inside
a styled Button), the Render fallback used ThemeTextPrimaryBrush — which is
dark (#142240, #1A2E1A, #281E3A) in light-background themes, making icons appear
completely black and unresponsive to theme changes.
Changes:
- IconControl.ForegroundProperty: Added as AddOwner of
TemplatedControl.ForegroundProperty (inherits: true). This means any IconControl
inside a Button or TemplatedControl automatically inherits that parent's Foreground
without needing an explicit binding. AffectsRender<IconControl>(ForegroundProperty)
ensures the visual updates when the inherited value changes on theme switch.
- Render fallback chain: Changed from `Stroke ?? ThemeHelper.GetBrush(...)` to
`Stroke ?? Foreground ?? Brushes.Gray`. Now a properly themed neutral color
flows naturally from the containing control rather than reaching into app
resources with a hard-coded key that returns wrong values for light themes.
- Icons.cs: Added `using Avalonia.Controls.Primitives` for TemplatedControl
reference.
- LightTheme.axaml: Changed ThemeNavText from #636380 (identical to DarkTheme's
value, making theme switching visually imperceptible in the sidebar) to #8080A8
— a slightly lighter and cooler blue-gray that sits better on the LightTheme
dark nav panel (#111118) and creates visible differentiation when toggling
between Dark and Light themes.
Practical effect: All sidebar nav icons now correctly adopt the ThemeNavTextBrush
color defined by the active theme. Switching from Dark to Light, Ember, Slate,
Azure, Sage, or Lavender now produces a visually distinct sidebar icon tint
instead of a uniform dark color across all themes.
Get notified about new releases