Info Badge non-intrusively signals "there is new content / unread count / something to notice" within an app; typical placements are NavigationView menu items, a corner of a button, or the end of a list item (WinUI official description: badging is a non-intrusive and intuitive way to display notifications or bring focus to an area within an app).
The styling and geometry align with the WinUI 3 / Windows App SDK InfoBadge (microsoft-ui-xaml, whose InfoBadge directory is byte-for-byte identical between winui3/release/2.0.1 — the WindowsAppSDK version used by the latest WinUI3 Gallery release v2.9.3 — and winui3/release/2.5.1):
InfoBadgeMinWidth / InfoBadgeMinHeight), max height 16 (InfoBadgeMaxHeight), unlimited width, corner radius = half the actual height (InfoBadge.cpp#OnSizeChanged).Value >= 0 shows a number (11px, InfoBadgeValueFontSize); otherwise, if there is an IconSource, it shows the icon; otherwise it is a 4×4 dot.InfoBadge.cpp#MeasureOverride returns a square when "width < height", so a single-number badge is a perfect circle rather than a narrow capsule.Viewbox is filled to "max height − padding" = 8px (the two InfoBadgeIconWidth / InfoBadgeIconHeight resources in the template are not referenced by the template — they are dead resources).The combination of the value and icon Props determines the form, derived line-by-line in alignment with InfoBadge.cpp#OnDisplayKindPropertiesChanged (Value takes precedence over Icon):
| Condition | Form | Corresponding WinUI |
|---|---|---|
value >= 0 | value | Value visual state |
has icon (or #icon slot) | icon | Icon / FontIcon visual state |
| neither | dot | Dot visual state (empty state) |
severity corresponds to the Style keys in InfoBadge_themeresources.xaml: each tier has Dot / Value / Icon variants with exactly the same background, differing only in "whether an IconSource is preset" and "whether the icon state adds Padding=0,4,0,2" (the latter is geometrically equivalent to IconInfoBadgeIconMargin in the icon state — see "Implementation notes").
severity | WinUI Style prefix | Background resource |
|---|---|---|
accent (default) | DefaultInfoBadgeStyle | AccentFillColorDefaultBrush |
attention | Attention*InfoBadgeStyle | SystemFillColorAttentionBrush |
informational | Informational*… | SystemFillColorSolidNeutralBrush |
success | Success*… | SystemFillColorSuccessBrush |
caution | Caution*… | SystemFillColorCautionBrush |
critical | Critical*… | SystemFillColorCriticalBrush |
Attention · Dot / Value / Icon
The badge's most common placements are navigation items and control corners. The badge itself is a purely decorative element, and the accessible name should hang on the control hosting it (Gallery does this: AutomationProperties.Name="Inbox, 5 notifications").
Refreshed 0 times
value is reactive: >= 0 shows the number, < 0 falls back to the dot form (WinUI's Value defaults to -1).
| Props | Type | Default | Description |
|---|---|---|---|
value | number | -1 | Badge value (Int32); >= 0 shows a number, < 0 falls back to icon / dot; aligned with WinUI Value |
severity | 'accent' | 'attention' | 'informational' | 'success' | 'caution' | 'critical' | 'accent' | Background preset; aligned with the six *InfoBadgeStyle sets |
icon | boolean | Component | null | — | Icon; true uses severity's built-in glyph, or pass an icon component directly; aligned with WinUI IconSource |
borderRadius | string | — | Corner radius; when omitted, aligned with OnSizeChanged's ActualHeight / 2 (fully rounded) |
label | string | — | Accessible name; when omitted the whole badge is aria-hidden (aligned with "InfoBadge has no AutomationPeer") |
| Slots | Description |
|---|---|
icon | Corresponds to WinUI IconSource; when provided, enters the Icon form and overrides the icon Prop and the built-in glyph |
Accessibility: WinUI's InfoBadge has no
AutomationPeer(Control.OnCreateAutomationPeeris not overridden, so it does not appear in the UIA tree); Gallery therefore hangs the accessible name on the parentNavigationViewItem. This component rendersaria-hidden="true"by default, does not take the tab order and does not intercept pointers;role="img"+aria-labelis rendered only when alabelis explicitly passed (standalone usage). The component does not hardcode any natural language.Implementation notes
- The form is derived live, not a
variantenum: inInfoBadge.cpp#OnDisplayKindPropertiesChanged,Value >= 0→Valuestate, otherwiseIconSource != null→FontIcon/Iconstate, otherwiseDotstate. This component'sdisplayKindcomputed corresponds to it word for word (including "Value takes precedence over Icon") and is exposed viadata-display-kindfor styling and test assertions.- The two icon forms are geometrically equivalent: in the template, the FontIcon state uses
InfoBadgePadding(overridden to0,4,0,2by*IconInfoBadgeStyle) +IconInfoBadgeFontIconMargin(4,0,4,2), and the Icon state usesInfoBadgePadding(0) +IconInfoBadgeIconMargin(4,4,4,4) — both yield "top+bottom 4+4, left+right 4+4" and an 8pxViewboxheight, so this library expresses both with a single "8px icon frame + 4px margin" rule and no longer needs apaddingProp.MeasureOverride's square rule is expressed in CSS: the final heights of the Value / Icon states are both clamped to 16 byInfoBadgeMaxHeight, so "square when width < height" is equivalent to adding amin-inline-size: 16pxto each of those two states; the Dot state's height isInfoBadgeMinHeight(4, equal toMinWidth) and is unaffected.- The value line height is locked to
lineHeightBase100(14px): 14 +ValueInfoBadgeTextMargin's bottom margin 2 = 16 =InfoBadgeMaxHeight, matching the result in WinUI where theTextBlock's natural line height (≈14.67px) is clamped to 16 byMaxHeight, and it does not drift with Web font metrics; the "the text's visual center is 1px above the badge's center" caused by the vertically asymmetric4,0,4,2margin is also preserved.InfoBadgeIconWidth/InfoBadgeIconHeightare not implemented: these two resources (12 / 8, and 12 / 9 under Light and HC themes) are not referenced inInfoBadge.xaml's template — the actual icon size is determined by theViewboxfilling the available height. Dead resources are not written into code, to avoid "restoring" according to them next time.- The five background tiers share one mapping with InfoBar:
SystemFillColor{Attention,Success,Caution,Critical}Brushare the same resources as InfoBar'sInfoBar*SeverityIconBackground, so it reusescolorCompoundBrandBackground/colorStatusSuccessForeground3/colorPaletteYellowForeground1/colorStatusDangerForeground3;informational'sSystemFillColorSolidNeutralBrushhas no equal-valued entry in Fluent 2 Web, so it takescolorNeutralForeground4by minimizingmax(light ΔE, dark ΔE)(CIE ΔE76;temp/pw-infobadge.mjsre-checks by measurement):
Severity WinUI original (Light / Dark) Our token ΔE (Light / Dark) accent system accent color colorCompoundBrandBackground— (see below) attention system accent color ( …ColorLight2)colorCompoundBrandBackground— (see below) informational #8A8A8A/#9D9D9DcolorNeutralForeground410.2 / 1.5 success #0F7B0F/#6CCB5FcolorStatusSuccessForeground30.4 / 30.8 caution #9D5D00/#FCE100colorPaletteYellowForeground126.5 / 23.0 critical #C42B1C/#FF99A4colorStatusDangerForeground37.3 / 15.2 foreground #FFFFFF/#000000colorNeutralForegroundInverted20.0 / 14.2
The accent colors are not in the repository (the exception clause of style-spec §2):AccentFillColorDefaultBrush/SystemFillColorAttentionBrushare both injected at runtime by the system accent color, and the blue in the real control and screenshots may be the user's custom color, so both take the Fluent default accent token, makingaccentandattentionthe same color on the Web — the semantic difference shows in the built-in glyph.success's dark tier has a large ΔE (30.8), the cost of keeping the same mapping as InfoBar; override with the local variables below if you need strict alignment with the real control.
Both the six background tiers and the foreground leave override hooks (same approach as InfoBar):.my-badge { --fui-info-badge-bg: #dff6dd; /* e.g. SystemFillColorSuccess original value */ --fui-info-badge-fg: #ffffff; }- The five built-in glyphs are all "bare glyphs", chosen by their shape: rendering the official Segoe Fluent Icons font at the real size (16px circle base + 8px glyph frame) and comparing (script
temp/infobadge-visual/glyph-badge-compare.mjs) confirms that the five glyphs preset by*IconInfoBadgeStyleare all without a circle base — the circle base is provided by the badge body. This is critical: InfoBar uses two stacked glyphs,F136(solid circle) +F13F(i), whileInformationalIconInfoBadgeStylegives only the singleF13Fglyph, so the InfoBar circular icon cannot be copied.
Severity WinUI IconSourceSegoe glyph Our icon attentionFontIconSource Glyph=Asterisk(8-point star)text_asterisk_16_filledinformationalFontIconSource Glyph=bare iinfo_16_regularsuccessSymbolIconSource Symbol=AcceptE8FBbare checkcheckmark_16_filledcautionSymbolIconSource Symbol=ImportantE171bare exclamationimportant_16_filledcriticalSymbolIconSource Symbol=CancelE711bare crossdismiss_16_filled
Known deviation: Fluent System Icons has no bare glyphi(an automatic scan over all 1,729 16px filled icons for "narrow bounding box + exactly two connected components + smaller upper component" returned an empty shortlist; seetemp/infobadge-visual/find-bare-i.mjs).info_16_filledis a "solid circle + cut-out i", so placing it directly yields a white disc + badge-colored i (foreground / background relationship inverted from WinUI; measured ink coverage 78% vs 22% for ours);info_16_regularis the samei(its subpaths are geometrically identical to the filled's cut-out i) with an extra 1-unit-wide white ring around it, and theiis still a white foreground — the only deviation is one extra thin ring, henceregularwas chosen. Use the#iconslot to swap in a hand-drawn glyph when exact matching is required.
Ink-size measurements (temp/pw-infobadge.mjs, section 3): on the WinUI side, the official Segoe Fluent Icons font is used to measure the glyph ink and line box, converted to 1× size by "theViewboxscales the line box (= 1em) to the 8px icon frame" (scripttemp/infobadge-visual/measure-segoe-ink.mjs); on our side, the pixels differing from the background are counted on 1:1 element screenshots to get the bounding box.
Severity Our icon ink (1x) WinUI 1x ink Δ attention6×6 7.0×7.0 −1.0 success6×5 8.0×5.5 −2.0 / −0.5 caution2×6 3.0×8.0 −1.0 / −2.0 critical6×6 5.5×5.5 +0.5 informational8×8 (thin ring + i) 0.8×3.3 (bare i) structural deviation
The first four tiers differ by 1–2px, originating in the two icon sets' different design whitespace: Fluent System Icons' 16px glyph ink occupies about 12/16 of the bounding box, while Segoe's symbol glyphs nearly fill the em box; the icon-frame mapping itself is correct (Fluent'sviewBox↔ Segoe's em box, both scaled byViewbox). Theinformationalrow is the structural deviation described above — WinUI'sF13Fis a 0.8px-wide thini(almost invisible at 1×), and since this library can't find a bareiin the official icon set, it falls back to "thin ring + i".- Reference-image cross-validation (C-tier evidence, comparing only scale-independent quantities): in the Gallery screenshots the accent badge heights are all 16px, the
Different InfoBadge Stylesrow is 16×16 (Icon) / 19×16 (Value "10") / 4×16 (Dot), and the "5" value badge in the NavigationView is a 16×16 perfect circle — each coincides withInfoBadgeMaxHeight=16,MeasureOverride's square rule, andInfoBadgeMinWidth/Height=4(seetemp/pw-infobadge.mjssection 4 and the screenshots undertemp/visual-infobadge/). The only difference is that the Value capsule is about 3px wider than the real control (aspect ratio 1.38 vs 1.19), from Web font metrics (Segoe UI vs Segoe UI Variable).- Known gaps: high-contrast themes are not implemented (under WinUI HC the background is
SystemControlHighlightAccentBrushand the foregroundSystemControlHighlightAltChromeWhiteBrush); the two dead resourcesInfoBadgeIconWidth / Heightare not implemented. The component has no Storyboard / VisualTransition, so motion andprefers-reduced-motionare not involved.- API differences from WinUI: WinUI throws
hresult_out_of_boundswhenValue < -1; this library treats it as< 0(falling back to Dot) and does not throw during rendering;IconSource→iconProp /#iconslot;TemplateSettingsis not exposed.