Enigma.Icons.Avalonia
1.0.0
dotnet add package Enigma.Icons.Avalonia --version 1.0.0
NuGet\Install-Package Enigma.Icons.Avalonia -Version 1.0.0
<PackageReference Include="Enigma.Icons.Avalonia" Version="1.0.0" />
<PackageVersion Include="Enigma.Icons.Avalonia" Version="1.0.0" />
<PackageReference Include="Enigma.Icons.Avalonia" />
paket add Enigma.Icons.Avalonia --version 1.0.0
#r "nuget: Enigma.Icons.Avalonia, 1.0.0"
#:package Enigma.Icons.Avalonia@1.0.0
#addin nuget:?package=Enigma.Icons.Avalonia&version=1.0.0
#tool nuget:?package=Enigma.Icons.Avalonia&version=1.0.0
Enigma.Icons.Avalonia
Icons for Avalonia — the Icon control, two XAML markup extensions, and
the extension methods that turn any IconGlyph into an Avalonia Geometry, Drawing or
DrawingImage. Ships with the 1,512 × 6 Phosphor glyphs of Enigma.Icons.Phosphor, and renders your
own SVGs just as happily.
What this package is
| You want… | Use |
|---|---|
The model, the parser, your own .svg files |
Enigma.Icons |
| The Phosphor artwork — 1,512 icons × 6 weights | Enigma.Icons.Phosphor |
Avalonia rendering — Geometry, markup extensions, the Icon control |
Enigma.Icons.Avalonia (this package) |
Target frameworks: net8.0, net10.0. Unlike its two siblings this package has no
netstandard2.0 target — Avalonia 12 ships net8.0 and net10.0 assets only, so a
netstandard2.0 consumer could not resolve it anyway.
It depends on Avalonia and on Enigma.Icons.Phosphor — which brings Enigma.Icons transitively —
and on nothing else.
Quick start
dotnet add package Enigma.Icons.Avalonia
One namespace declaration reaches the control and both markup extensions:
xmlns:ei="https://github.com/josueclement/Enigma.Icons"
<ei:Icon Kind="Acorn" Weight="Duotone" Size="24"
Foreground="{DynamicResource SystemControlForegroundAccentBrush}" />
The per-namespace using: forms remain the documented fallback — Avalonia's using: mapping covers
one CLR namespace and not its sub-namespaces, so that route needs two declarations
(xmlns:ei="using:Enigma.Icons.Avalonia" for the control and
xmlns:eim="using:Enigma.Icons.Avalonia.Markup" for the extensions).
Nothing goes into
App.axaml.Iconderives fromControl, notTemplatedControl, and renders itself. The package ships no XAML and no theme resources, so there is no<StyleInclude>to add and no resource key to get wrong. Add the package, declare the namespace, use the control.
And from C#:
using Avalonia.Media;
using Enigma.Icons.Avalonia;
using Enigma.Icons.Phosphor;
Geometry geometry = PhosphorIconSet.Instance
.GetGlyph(PhosphorIcon.Acorn, PhosphorWeight.Bold)
.ToGeometry();
The Icon control
| Property | Default | What it does |
|---|---|---|
Kind |
Acorn (enum value 0) |
The built-in Phosphor icon to draw |
Weight |
Regular |
Thin, Light, Regular, Bold, Fill, Duotone |
IconSet |
null |
A custom IIconSet. When set, it wins over Kind/Weight |
IconName |
null |
The name to resolve against IconSet |
Variant |
null |
The variant of IconName, or the set's default |
Foreground |
inherited | The brush every layer paints with |
Size |
16 |
The measured size on both axes |
Stretch |
Uniform |
None, Uniform, UniformToFill, Fill |
Four behaviours are worth stating outright:
Foregroundinherits. It re-ownsTextElement.ForegroundProperty, which is an inheriting property, so an icon inside aButton, aMenuItem, aTextBlock— any text scope — picks up that scope's brush and follows a theme switch with no binding written by you. WhenForegroundresolves tonullthe control paints nothing; it does not fall back to black.- An explicit
Width/Heightwins overSize.Sizeis the measured square; the framework's own explicit-size coercion takes precedence over it. Rendernever throws. A missing glyph, an unresolvable name, or a misbehaving third-party icon set all paint nothing — a throwing render pass would take down the XAML previewer's surface for the whole window, not just the icon.- Path data is parsed once per glyph, not once per frame. A resize, a theme switch or a scroll
through a virtualized list re-renders every visible icon; the parsed geometry is held against the
glyph itself, so those passes cost no parsing at all — and many controls showing the same icon
share one parse. The cache holds its glyphs weakly, so a custom
IIconSetthat goes out of scope is collected normally.
<Button Content="Delete">
<Button.Template>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<ei:Icon Kind="Trash" />
<ContentPresenter />
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
Accessibility. Icon is decorative by default: Focusable is false and a screen reader skips
it. Set AutomationProperties.Name when the icon carries meaning of its own, and it joins the
automation content view.
Control or markup extension?
A markup extension is evaluated once, at load time. It therefore cannot follow a bound brush, a
DynamicResource, or a theme switch — not as a design choice, but structurally. The control can,
because it resolves its brush at render time.
- Use
ei:Iconfor anything themed, bound, or interactive. This is most icons in most apps. - Use the markup extensions for a static
Path.DataorImage.Sourcethat never changes.
There is one more deliberate asymmetry: the markup extensions fail fast — a bad icon or weight in
XAML throws at load time, because that is an authoring error you want to see — while Icon.Render
never throws.
The markup extensions
<Path Data="{ei:IconGeometry Acorn, Weight=Bold}" Fill="Black" Stretch="Uniform" />
<Image Source="{ei:IconImage Acorn, Weight=Fill, Brush=Red}" Width="24" Height="24" />
Both take the icon as a positional argument and default Weight to Regular; IconImage also takes
a Brush, defaulting to black. It is called IconImage rather than IconSource because it returns
a DrawingImage and Avalonia already has an IconSource concept of its own.
The extension methods
Geometry ToGeometry(this IconGlyph glyph);
Drawing ToDrawing(this IconGlyph glyph, IBrush brush);
DrawingImage ToDrawingImage(this IconGlyph glyph, IBrush brush);
They take an IconGlyph — from any IIconSet — so nothing here is Phosphor-specific.
ToGeometry collapses a multi-layer glyph into a GeometryGroup, and per-layer opacity is lost.
A Geometry has no per-child opacity and one shared fill rule, so every layer paints at full
opacity. For the two-layer Duotone weight that means the backing shape comes out solid — visually
wrong, and deliberately allowed, because a single Geometry is what Path.Data needs. Use
ToDrawing, or the Icon control, for duotone; both walk the layers and honour each one's opacity.
Every call parses afresh, and the result is yours to keep or mutate. Unlike the Icon control,
which caches its parsed geometry per glyph because it never hands it out, these methods return an
independent object each time — so setting Transform on one, or putting it in a GeometryGroup,
can never disturb another caller holding the same icon.
Works with any IIconSet
The extension methods and the control's IconSet / IconName / Variant path take any icon set,
including an SvgIconSet over a folder of your own artwork — the built-in set has no privileged
route:
using Enigma.Icons;
// Build the set once — at start-up, or as a ViewModel property — and bind it.
IIconSet mine = SvgIconSet.FromDirectory("Assets/Icons", name: "House");
<ei:Icon IconSet="{Binding MyIconSet}" IconName="logo" Variant="bold" Size="32" />
Stroked and translucent layers survive the trip: ToDrawing and the control build a Pen from the
layer's stroke width, cap and join, and honour a layer's own stroke colour when it names one. See
Enigma.Icons for the set factories and the parser's
supported subset.
Trimming and AOT
The package is marked IsTrimmable and IsAotCompatible on the modern target frameworks, and builds
free of IL2xxx/IL3xxx warnings.
Gallery
The repository ships a gallery sample that filters all 1,512 icons by name as you type, switches
between the six weights, and offers size and colour controls — click an icon to copy its XAML
snippet:
samples/Enigma.Icons.Avalonia.Gallery.
Licence
MIT — see LICENSE.md, which ships in this package.
The icon artwork is separately MIT-licensed by Phosphor Icons; its
notice travels with
Enigma.Icons.Phosphor,
the package that carries the artwork.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Avalonia (>= 12.1.0)
- Enigma.Icons.Phosphor (>= 1.0.0)
-
net8.0
- Avalonia (>= 12.1.0)
- Enigma.Icons.Phosphor (>= 1.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 78 | 7/31/2026 |
Enigma.Icons.Avalonia 1.0.0 — initial release. Avalonia rendering for Enigma.Icons: the Icon control (no StyleInclude needed; inherits Foreground and follows theme switches), the {ei:IconGeometry} and {ei:IconImage} markup extensions, and Geometry / Drawing / DrawingImage conversion extensions. Supersedes the retired PhosphorIconsAvalonia package — new identity, no upgrade path. See RELEASENOTES.md for the full details.