| name | winui-design |
|---|---|
| description | WinUI 3 UI design and XAML correctness — layout planning, control selection, Fluent Design, theming (Light/Dark/HighContrast), typography styles, spacing, brushes, accessibility, data binding review. Use when designing new pages, converting from WPF/Electron/web, reviewing XAML, fixing theme issues, or applying Fluent Design. |
Before picking controls, search the catalogue. This skill ships
winui-search.exealongside thisSKILL.md. It indexes 100+ WinUI Gallery controls, every Windows Community Toolkit scenario, and a curated set of platform integration patterns (JumpList, Share, file pickers, drag-drop). Use it to ground every control choice in a real shipping sample before writing any XAML — this is the difference between guessing property names and copying canonical code..\winui-search.exe search "<feature 1>" "<feature 2>" ... # batch one focused query per feature .\winui-search.exe get <id 1> <id 2> ... # batch up to 3 IDs — full XAML + C# + pitfall notes .\winui-search.exe list # browse all patterns (heavy — prefer search) .\winui-search.exe update # force refresh nowWorkflow: in one
searchcall, list every feature you need for the current page (one focused query per feature, not a bag of keywords) → from each shortlist pick the best ID → grab full code withget(batch up to 3 IDs per call) → then write XAML using those samples as reference. Do NOT interleave searching with coding — front-load all lookups, then code. BM25 rewards focused per-query phrasing, so keep each query about one control or pattern.
| App Type | Anchor Control | Reference App |
|---|---|---|
| Settings / config tool | NavigationView Left + SettingsCard |
Windows Settings |
| Document / session editor | TabView + full-width content |
Windows Terminal, Notepad |
| Hierarchical browser | TreeView + ListView + BreadcrumbBar |
File Explorer |
| Developer tool / dashboard | NavigationView + card layout |
Dev Home |
| Single-purpose utility | Mode switcher + compact grid | Calculator |
Navigation: 2-7 sections → NavigationView; document tabs → TabView; breadcrumb trail → BreadcrumbBar; 2-3 modes → SelectorBar.
Data display: Vertical list → ListView; tiles/grid → GridView or ItemsRepeater + UniformGridLayout; hierarchy → TreeView; tabular → ListView with Grid column headers; master-detail → ListView + detail Grid.
Input: Text → TextBox; number → NumberBox; search → AutoSuggestBox; date → CalendarDatePicker; boolean → ToggleSwitch; pick one from 2-3 → RadioButtons; pick one from 4+ → ComboBox.
Feedback: Blocking decision → ContentDialog; contextual action → Flyout/MenuFlyout; onboarding → TeachingTip; inline status → InfoBar; system notification → AppNotification.
For app silhouette, responsive breakpoints, adaptive XAML, title bar composition, panel choice, and initial window size, use winui-layout before writing page XAML. Return here for control lookup, theming, typography, brushes, accessibility, and binding correctness.
Minimum layout defaults: content fills the window, ordinary pages use a Grid skeleton, StackPanel is local-only, and floating cards on empty backgrounds need a strong product reason.
Use winui-layout to derive the initial window size from the page layout. WinUI 3 has no SizeToContent; do not fake it by setting Width or Height on the root element because that clips content instead of resizing the app window.
If the user asks for UI validation, see winui-ui-testing Step 3.5 to verify layout and window fit against the visual checklist.
| ❌ Don't | ✅ Do Instead |
|---|---|
| Centered floating card on background | Content fills window with padding |
| Custom pill/segment tab switcher | NavigationView Top or SelectorBar |
| Equal-width 50/50 column split | Fixed sidebar (300-360px) + flexible main |
Hardcoded colors (#FF0000) |
{ThemeResource} brushes |
ScrollViewer around ListView |
ListView has built-in scrolling |
| Custom ControlTemplate for standard controls | Built-in controls with style overrides |
{ThemeResource BrushName}at usage sites — updates on theme change{StaticResource}withResourceKeyredirects inside theme dictionaries — zero allocationResourceKeymust end inBrush(target theSolidColorBrush, not theColor)- Always define all three variants:
x:Key="Light",x:Key="Dark",x:Key="HighContrast"— never usex:Key="Default" - Verify runtime theme switching:
{ThemeResource}updates;{StaticResource}does not
<!-- Correct: StaticResource redirect in theme dictionary -->
<StaticResource x:Key="MyBrush" ResourceKey="ControlFillColorDefaultBrush" />
<!-- Wrong: inline SolidColorBrush allocates new object -->
<SolidColorBrush x:Key="MyBrush" Color="{StaticResource ControlFillColorDefault}" />Only 8 system color brushes allowed in HC dictionaries:
| Background | Foreground | Use Case |
|---|---|---|
SystemColorWindowColorBrush |
SystemColorWindowTextColorBrush |
General content |
SystemColorHighlightColorBrush |
SystemColorHighlightTextColorBrush |
Selected/hover |
SystemColorButtonFaceColorBrush |
SystemColorButtonTextColorBrush |
Buttons |
SystemColorWindowColorBrush |
SystemColorHotlightColorBrush |
Hyperlinks |
SystemColorWindowColorBrush |
SystemColorGrayTextColorBrush |
Disabled content |
HC prohibitions: No hardcoded colors, no opacity, no accent colors, no regular WinUI brushes, no SystemColor* in Light/Dark dicts. Use empty HC dict when WinUI defaults suffice. Set HighContrastAdjustment = None at app level.
| Style | Size | Weight | Use For |
|---|---|---|---|
CaptionTextBlockStyle |
12px | Regular | Small labels, timestamps |
BodyTextBlockStyle |
14px | Regular | Body text (default — don't set explicitly) |
BodyStrongTextBlockStyle |
14px | Semibold | Emphasized body text |
SubtitleTextBlockStyle |
20px | Semibold | Section headers, card titles |
TitleTextBlockStyle |
28px | Semibold | Page titles |
TitleLargeTextBlockStyle |
40px | Semibold | Large feature titles |
DisplayTextBlockStyle |
68px | Semibold | Hero text |
Use SemiBold, never Bold. Minimum 12px. BasedOn styles must not re-declare inherited properties.
- 4px grid: margins, padding, sizes must be multiples of 4 (4, 8, 12, 16, 24, 32, 48)
ControlCornerRadius(4px) for controls,OverlayCornerRadius(8px) for overlays — never hardcodeRowSpacing/ColumnSpacinginstead of spacer elementsMinHeight/MinWidthinstead of fixed sizing- No negative margins
Don't set WinUI default values — blocks future updates:
BodyTextBlockStyleon TextBlock,TextFillColorPrimaryBrushforeground,TextWrapping="NoWrap",Padding="0",Margin="0"
| Surface | Background | Border |
|---|---|---|
| Flyouts, tooltips | AcrylicBackgroundFillColorDefaultBrush |
SurfaceStrokeColorFlyoutBrush |
| UI surfaces | AcrylicBackgroundFillColorBaseBrush |
SurfaceStrokeColorDefaultBrush |
Use BackgroundSizing="InnerBorderEdge" on bordered acrylic. ThemeShadow requires Translation="0,0,32" and 12px parent padding.
{x:Bind}over{Binding}, explicitMode=OneWay/TwoWay,x:DataTypeonDataTemplate- TextBox
x:Bind TwoWay— always addUpdateSourceTrigger=PropertyChangedso the ViewModel updates on each keystroke instead of waiting forLostFocus. Without it, UIA automation (set-value) and programmatic changes won't commit to the ViewModel.<TextBox Text="{x:Bind ViewModel.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
- Commands over Click/Tapped handlers (MVVM)
VisualStateManagerfor visual property changes, not code-behind- No
IValueConverter— preferx:Bindwith functions
Bool negation and Visibility functions — define static methods in code-behind:
// In code-behind (e.g., MainPage.xaml.cs)
public static Visibility BoolToVisibility(bool value) =>
value ? Visibility.Visible : Visibility.Collapsed;
public static Visibility InvertBoolToVisibility(bool value) =>
value ? Visibility.Collapsed : Visibility.Visible;
public static bool IsNotBusy(bool isLoading) => !isLoading;<!-- Usage in XAML -->
Visibility="{x:Bind local:MainPage.BoolToVisibility(ViewModel.IsLoading), Mode=OneWay}"
IsEnabled="{x:Bind local:MainPage.IsNotBusy(ViewModel.IsLoading), Mode=OneWay}"❌ NEVER use Converter={x:Null} — it crashes at runtime.
AutomationProperties.Nameon icon-only controlsAutomationProperties.AutomationIdon all interactive controls- Semantic controls (
Button,HyperlinkButton) — not clickableBorder/TextBlock DividerStrokeColorDefaultBrushfor dividers
Setting attached properties in code-behind — WinUI attached properties use static methods, NOT object initializer syntax:
using Microsoft.UI.Xaml.Automation; // required for AutomationProperties
// ❌ WRONG — object initializer doesn't work for attached properties
var btn = new Button { AutomationProperties = { AutomationId = "BtnSave" } };
// ✅ CORRECT — static setter method
var btn = new Button { Content = "Save" };
AutomationProperties.SetAutomationId(btn, "BtnSave");
AutomationProperties.SetName(btn, "Save button");
Grid.SetRow(btn, 1);
Grid.SetColumn(btn, 0);
ToolTipService.SetToolTip(btn, "Save the current document");- Self-closing tags for childless elements
- Styles referenced with
{StaticResource}not{ThemeResource} - No
pxsuffix on numeric values, no commented-out XAML - Consistent attribute order: x:Name, AutomationProperties, layout, content, style
| File | Read when... |
|---|---|
references/approved-brushes.md |
Looking up correct WinUI brush names and usage rules |
references/theme-aware-resources.md |
Implementing ThemeResource/StaticResource, High Contrast, acrylic pairings |
references/code-review-checklist.md |
Reviewing XAML changes for correctness |
references/pr-review-patterns.md |
Applying concrete review fixes and patterns |
references/control-styles.md |
Customizing built-in control styles |
references/typography-and-spacing.md |
Detailed type ramp, spacing grid, and sizing examples |
references/colors-and-materials.md |
Theme brush catalog, Mica/Acrylic surface pairings, material usage |
references/iconography-and-motion.md |
Icon guidelines, animation patterns, connected animations |
Sibling skill: winui-layout |
Page silhouette, responsive breakpoints, title bar layout, layout panels, content spacing, and initial window sizing |