Skip to content

About

Custom Avalonia Themes developed by Devolutions

Resources

Security policy

Stars

82 stars

Watchers

8 watching

Forks

Repository files navigation

image

avalonia-themes

Custom Avalonia Themes developed by Devolutions

➡️ MacOS Theme

➡️ DevExpress Theme

➡️ 🚧 WinUI Theme

➡️ Linux Theme

➡️ Avalonia Controls

Package Compatibility

Avalonia 12 line. Packages 2026.6.17-avalonia12 and later are on the Avalonia 12 line. The first stable Avalonia 12 release is 2026.6.23, and 2026.6.16 is the last stable release compatible with Avalonia 11.

Maintenance-only fixes for the Avalonia 11 line may still be published as 2026.6.16.x for a limited time. See the Avalonia 11 -> 12 breaking changes for upstream migration guidance.

Sample App

Contributors can use the SampleApp to test, debug and document styles for the various controls under each theme.

The theme selector groups themes under Linux, MacOS, and Windows. Avalonia Fluent and Avalonia Simple appear first without a group header. Its popup grows to fit the themes, limited only by the available screen space.

Debugging

The SampleApp attaches the Avalonia Dev Tools for inspecting controls (open with F12).

Avalonia Accelerate Controls

We will soon start to add styles for at least some Avalonia Accelerate controls, starting with TreeDataGrid in the DevExpress theme.

To view and test Accelerate-licensed controls in the SampleApp:

  1. Create a .env file in the repository root.
  2. Add your license key: AVALONIA_LICENSE_KEY=your_key_here.
  3. Rebuild the solution.

Note: If the controls don't appear or you see build errors, you may need to force a NuGet restore or invalidate your IDE caches (e.g., File > Invalidate Caches in Rider) to update the conditional package dependencies.

Testing

There is limited visual regression testing available. Native themes use tracked images in tests/Devolutions.AvaloniaControls.VisualTests/Screenshots/Baseline/{CurrentOS}/{Theme}; non-native themes use personal images in Screenshots/LocalBaselines/{Theme}. Images from other operating systems are never compared. Personal baselines are gitignored and belong to this machine and worktree. Diffs for failing tests are saved to tests/Devolutions.AvaloniaControls.VisualTests/Screenshots/Test-Diffs. Screenshots are captured at a fixed width (1200) with auto-calculated content height (capped at 3000) to cover below-the-fold examples without requiring manual page-by-page configuration.

Limitations

  • Interactive behaviours (e.g. pointerOver, popUpOpen, focus, etc.) are not tested
  • Accelerate controls that depend on a licence (e.g. TreeDataGrid) are not tested

Canonical and Personal Baselines

Only screenshots from a theme's target platform are canonical and required in PRs:

Theme Canonical platform
DevExpress, WinUiClassic, WinUiMica Windows
MacClassic, LiquidGlass macOS
Linux/Yaru Linux

Cross-platform screenshots are a local developer convenience, not required PR coverage. In particular, Windows WinUI changes do not require macOS or Linux baseline images. Adding a new control still requires appropriate target-platform visual coverage.

Pages marked "same as reference" in the catalog compare the two themes' rendered output directly instead of storing a separate PNG for the delegating variant.

Before CI owns baseline generation, native themes always compare with tracked images; stale personal copies of those themes are ignored. Non-native themes compare only with personal images. For example, on macOS, MacClassic/LiquidGlass use tracked images, while DevExpress/WinUI/Linux use personal images.

A missing image from the appropriate set fails with Missing baseline. A differing image fails with Visual regression. There is no missing-local failure for a native theme with a valid tracked image.

Personal images live directly under LocalBaselines/{Theme}/, with no OS subdirectory. When migrating an older local tree, remove the other OS trees before moving your current OS's theme folders up one level: Linux is both an OS directory name and a theme name. Do not reuse other OS images. Each machine generates its own personal set.

Temporary local publishing workflow (until GitHub runners own canonical generation):

  • --update-baselines approves intentional changes: native themes write only tracked images; non-native themes write only personal images. It does not create duplicate native personal images.
  • Review and commit only intentional target-platform changes in Screenshots/Baseline/. The rest remain in gitignored LocalBaselines/.
  • Initialize a new worktree with ./devtest visual --initialize-local-baselines, on the clean starting revision before making changes. This is capture-only: it writes non-native personal screenshots without comparing images or running WinUI reference-theme identity checks. Tracked images are never written or tested in this operation.
  • If LocalBaselines is non-empty, the command warns and requires typing y before overwriting selected non-native images. Any other answer or end of input cancels before capture. Unselected images remain unchanged; use the unfiltered command for a full set. Agents must surface this overwrite confirmation to the user and must not answer it automatically or pipe y without explicit overwrite approval.
  • Agents always ask once at the start of a new session whether to initialize the full development set, even if the planned task is non-visual. Do not generate from an already modified tree without explicit user approval.
  • Personal images are worktree-specific: do not automatically copy or share them via worktree setup. Existing images are not refreshed automatically after a rebase or merge; review intentional changes before updating them.

The planned GitHub workflow will replace this temporary local publishing step. See the CI proposal.

Note: We're showing single quotes here, since in interactive bash/zsh (Linux/Mac), ! triggers history expansion, so the following term is interpreted as a history variable, unless the filter string is single-quoted ('...') instead of double-quoted. However, on Windows only PowerShell supports the single quotes - so you might want to get used to double quotes if you're always on Windows.

Usage

  • dotnet test - runs all tests
  • dotnet test --filter 'DisplayName~VisualRegressionTests' - runs only visual regression tests
  • dotnet test --filter 'DisplayName!~VisualRegressionTests' - runs only non-visual tests
  • dotnet test --filter 'DisplayName~DevExpress' - runs tests for all controls implemented in DevExpress
  • dotnet test --filter 'DisplayName~Button' - runs tests for Button under each of the themes it's implemented in
  • dotnet test --list-tests - lists all test cases

Combining DisplayName filters

The xUnit/VSTest filter syntax uses & for AND, | for OR and ! for NOT.

  • dotnet test --filter 'DisplayName~Button&DisplayName~DevExpress' - runs only tests whose display name contains both Button and DevExpress
  • dotnet test --filter 'DisplayName~ContextMenu|DisplayName~MenuFlyout' - runs tests containing either ContextMenu or MenuFlyout
  • dotnet test --filter 'DisplayName~Button&DisplayName!~HyperlinkButton' - runs tests containing Button but excluding HyperlinkButton

🆕 Shorthand command & cleaner output:

  • ./devtest (macOS/Linux/Git Bash) or .\devtest (Windows PowerShell/CMD) - runs all tests with a succinct summary.
  • ./devtest visual - runs all tests in Devolutions.AvaloniaControls.VisualTests.
  • ./devtest nonvisual - runs all tests in Devolutions.AvaloniaControls.Tests.
  • ./devtest functional - alias for nonvisual.
  • ./devtest --filter EditableCombo - shorthand for (DisplayName~EditableCombo).

The wrapper prints a visual regression summary for screenshot mismatches and missing baselines, including the theme, page, variant, and output path. Reference-theme equality failures also appear in this table, with one row per mismatching light/dark variant.

Updating baseline screenshots when changes are intentional:

  • ./devtest visual --initialize-local-baselines - captures non-native personal images without comparisons; asks before overwriting a non-empty personal set.
  • ./devtest visual --update-baselines - updates tracked native images and personal non-native images for intentional changes.
  • ./devtest --update-baselines - runs all projects with baseline updates enabled.
  • macOS/Linux: UPDATE_BASELINES=true dotnet test [filters]
  • Windows (PowerShell): $env:UPDATE_BASELINES="true"; dotnet test [filters]; Remove-Item env:UPDATE_BASELINES
  • Windows (Command Prompt): set UPDATE_BASELINES=true && dotnet test [filters] && set UPDATE_BASELINES=

🤍🖤 All tests are run for light & dark mode However to keep things reasonably quick, the dark mode test only runs if the light mode test for the same control has passed. This can lead to missed issues, when both versions have different problems. (If in doubt, update, then delete the new dark baseline shot, and run the test again (light will no longer fail, and you can see what happens in dark))

AI Assistant Instructions

If you're an AI assistant (like GitHub Copilot or Claude Code) working on this repository, comprehensive guidelines are available in .claude/CLAUDE.md.

This includes:

  • Repository structure and architecture
  • Development workflows and commands
  • Coding standards and best practices
  • Version control rules and commit guidelines
  • Custom commands for theme switching and development

About

Custom Avalonia Themes developed by Devolutions

Resources

Security policy

Stars

82 stars

Watchers

8 watching

Forks

Releases

Packages

Used by

Contributors

Languages