Add Reactor (Microsoft.UI.Reactor) dotnet new templates - #6620
Conversation
Adds four Reactor project templates to the Microsoft.WindowsAppSDK.WinUI.CSharp.Templates dotnet-new pack, mirroring the WinUI templates but for Microsoft.UI.Reactor (pure C#, no XAML): - Reactor Blank App (reactor, reactor-blank) - Reactor MVU App (reactor-mvu) - Reactor NavigationView (reactor-navview) - Reactor TabView App (reactor-tabview) Wired into dev/Templates/templates.props via the DotnetNewOnlyProjectTemplate slot (dotnet-new only, no VSIX, no manifest; Reactor apps run unpackaged). Each shares a common csproj referencing Microsoft.UI.Reactor + Microsoft.WindowsAppSDK, bundles the WinAppSDK runtime self-contained, and enables the Debug-only Reactor devtools surface. README and Test-DotnetNewTemplates.ps1 updated to document and validate the new templates. Validated end-to-end: pack -> install -> dotnet new -> build (Debug + Release) for all four templates. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
TitleBar(...).Icon(FontIcon(...)) threw System.ArgumentException (E_INVALIDARG) at runtime when Reactor set TitleBar.IconSource on Windows App SDK 2.1.3, so the scaffolded Blank, MVU, and TabView apps crashed on launch. The glyph was only a placeholder, so drop the icon; the title bar still shows the title text and all four templates now launch cleanly (validated with dotnet run). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
microsoft/microsoft-ui-reactor#855 fixes the IconResolver FontSize=NaN crash (FontIcon in an IconSource slot without an explicit size threw ArgumentException from TitleBar.set_IconSource). That fix ships in Microsoft.UI.Reactor 0.1.0-preview.12, so restore the placeholder title-bar app-mark icon in the Blank, MVU, and TabView templates and bump the default reactorVersion 0.1.0-preview.11 -> 0.1.0-preview.12 across all four templates. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
/azp run |
|
Azure Pipelines: Successfully started running 2 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. |
The template smoke-test stage installed only .NET SDK 8.0.x, so scaffolding and building the Reactor templates failed with NETSDK1045 (Reactor targets net10.0 and declares a [10.0,) sdk-version constraint). The WinUI templates auto-detect their TFM from the active SDK, so they built net8.0 and passed, masking the gap. Add a second UseDotNet@2 step (param reactorDotnetSdkVersion, default 10.0.x) to the shared Test-Stage template so the agent has the .NET 10 SDK. Verified locally that the WinUI templates still build cleanly on the .NET 10 SDK, so existing coverage is unaffected. Both the official and PR pipelines consume this shared stage. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines: Successfully started running 2 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. |
| <Platforms>x64;ARM64;x86</Platforms> | ||
| <UseWinUI>true</UseWinUI> | ||
| <!-- Reactor apps run unpackaged. --> | ||
| <WindowsPackageType>None</WindowsPackageType> |
There was a problem hiding this comment.
Why not make them packaged apps? Dotnet run supports packaged apps now.
@azchohfi You can reference the existing winui templates, when you launch them, there will be an app id.
There was a problem hiding this comment.
Good call - done in 94e206a. All four are single-project MSIX now, matching the WinUI templates: EnableMsixTooling, a Package.appxmanifest, and a reference to Microsoft.Windows.SDK.BuildTools.WinApp so plain dotnet run registers the loose layout and launches with package identity.
| { | ||
| public override Element Render() | ||
| { | ||
| var (selectedIndex, setSelectedIndex) = UseState(0); |
There was a problem hiding this comment.
Hi @azchohfi, can we integrate the tabs into the title bar? That would be cleaner and save some vertical space.
You can reference the winui-tabview template about the config.

in contrast, the current reactor-tabview is stacking tabs below title bar:

There was a problem hiding this comment.
Done in c15e219 - the tabs are in the title bar now, following the winui-tabview config: ExtendsContentIntoTitleBar, the tab strip footer registered via SetTitleBar, an app icon in TabStripHeader, and the footer MinWidth tracking TitleBar.RightInset converted to DIPs so the caption buttons don't overlap tabs on high-DPI displays.
One thing worth flagging in this file: the page surface sets MinHeight from the window height. That's a workaround - Reactor tab content currently sizes to its text instead of filling the tab body, so without it the background is two-tone where the winui-tabview equivalent is uniform. Filed upstream as microsoft/microsoft-ui-reactor#914; once that's fixed the MinHeight can come out and the page helper goes back to just a background + padding.
Review feedback from @DinahK-2SO on #6620: - Remove the explanatory comment block from the Reactor launchSettings.json files (the content overlapped the package README). - Give the MVU, NavigationView, and TabView templates their own icon.png (reusing the existing WinUI mvvm/navigation/tabview template icons) instead of all reusing the blank-app icon. The packaging/taskbar-icon, tabs-in-title-bar, and winui-* short-name comments are still open pending a check with the Reactor team. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Review feedback from @DinahK-2SO on #6620: give each Reactor template a winui-reactor* alias (winui-reactor, winui-reactor-mvu, winui-reactor-navview, winui-reactor-tabview) so they also surface under 'dotnet new list winui' alongside the other WinUI templates. README updated to note the aliases. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Review feedback from @DinahK-2SO on #6620: instead of stacking a separate TitleBar row above the TabView, put the tabs up in the title bar (Edge/Terminal style) to look cleaner and save vertical space. Uses supported Reactor APIs: UseWindow().NativeWindow with ExtendsContentIntoTitleBar + SetTitleBar, the TabView TabStripHeader (app name at the leading edge) and TabStripFooter (draggable region), and UseDpi + UseWindowSize to reserve the caption-button inset (RightInset) across DPI and resize. Verified by scaffolding the template, building, running, and screenshotting the window: the tabs render inline in the title bar with the caption buttons clear. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Per review direction, the four Reactor templates now:
1. Are single-project MSIX packaged (like the WinUI templates) instead of
unpackaged. Each gains app.manifest, Package.appxmanifest (EntryPoint
Windows.FullTrustApplication since Reactor has no XAML App class), the shared
Assets, and PublishProfiles. The csproj switches to EnableMsixTooling +
Microsoft.Windows.SDK.BuildTools + Microsoft.Windows.SDK.BuildTools.WinApp so
'dotnet run' registers a loose package and launches with MSIX identity.
templates.props sets RenameManifestFrom and the template.json files gain the
publisher / guid / build-tools-version symbols and the \\$
modifier.
2. Visually match their WinUI counterparts:
- reactor -> title bar (app icon) + empty content (blank canvas).
- reactor-mvu -> centered 'Hello, WinUI!' + [+]/[-] icon counter (keeps the
UseReducer MVU pattern under the same UI).
- reactor-navview -> title bar + NavigationView Home/About + built-in Settings;
pages render 'Title' + 'This is the X page'.
- reactor-tabview -> MicaAlt, app-icon TabStripHeader, closable Home/About tabs
with a '+' add button, tabs in the title bar.
Validated end-to-end for all four: pack -> install -> scaffold -> build ->
dotnet run (launches packaged with identity) -> screenshot matches the WinUI
counterpart. README updated (templates are now packaged).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…font parity - MVU greeting is now 'Hello, Reactor!' (was 'Hello, WinUI!'). - Switch the Reactor text from Heading()/.SemiBold() (raw 28px Bold-700) to the type-ramp factories Title()/BodyStrong()/Body(), which apply the actual WinUI styles (TitleTextBlockStyle 28px Semibold-600, BodyStrongTextBlockStyle, BodyTextBlockStyle). This makes the Reactor headings/body render with the same weight and Segoe UI Variable optical size as the WinUI templates instead of a heavier bold. Applied to the mvu, navview, and tabview page text. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The WinUI TabView template's pages set Background=SolidBackgroundFillColorTertiaryBrush, which covers the window's Mica in the tab content area. The Reactor version left the pages transparent, so MicaAlt showed through the content. Wrap the tab page content in a Border painted with that same tertiary brush so the content is a solid surface and only the tab strip / title bar show Mica, matching X_Tab. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The solid tertiary page background only covered the text at the top because Reactor sizes the tab content to the element's desired size. Force the page Border to HorizontalAlignment/VerticalAlignment Stretch so the solid surface fills the whole tab content region, matching the WinUI TabView template (verified: the content is a uniform solid fill down to the window bottom). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Match the WinUI TabView template's uniform tertiary content background by sizing the shared page surface to the window height, so it fills the whole tab content area instead of shrinking to its text (two-tone with Mica below). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1
Match the WinUI NavigationView template's shell: the title bar owns the back and pane toggle buttons, and NavigationView's own copies are hidden. Switch from hand-rolled tag state to Reactor's navigation handle (UseNavigation + NavigationHost), so the title bar back button is wired by .WithNavigation(nav) and tracks the back stack instead of never appearing. Also request the tall title bar layout the WinUI template uses. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1
NavigationView opens and closes its pane on its own (light dismiss, display mode changes), so a separate IsPaneOpen state copy drifted out of sync and the title bar toggle needed two clicks to take effect. Flip IsPaneOpen on the control directly, the same way the WinUI template's code-behind does. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1
Reactor's NavigationHost slides pages in from the side, while WinUI's Frame defaults to an entrance transition that rises the new page up into place. Slide from the bottom so switching pages animates the same way. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1
The Reactor templates carried long comments explaining Reactor concepts and how they differ from XAML, which made them read like documentation rather than a starting point. Keep only the brief, functional comments the XAML templates use, and a single pointer to the Reactor project info. Also drop the explicit navigation transition from reactor-navview: matching the XAML Frame's entrance animation added verbosity and called out a difference between the two, so use Reactor's default instead. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1
Microsoft.UI.Reactor is prerelease and its API may still change, so label the templates accordingly: add `(Experimental)` to each template name, an `Experimental` classification so it shows in the dotnet new tags column, and a note in each description and in the README. Also correct the templates.props comment, which still described the Reactor apps as unpackaged with RenameManifestFrom unset; they are packaged (single-project MSIX) and do set it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1
The templates tripped four of Reactor's analyzers, so a freshly scaffolded project did not build clean: - REACTOR_A11Y_001 (x2): the MVU counter's icon-only buttons had no accessible name. Add .AutomationName(). - REACTOR_A11Y_002: the TabView tab strip icon is decorative. Mark it .AccessibilityHidden(). - REACTOR_HOOKS_013: the initial tab array was reallocated on every render though only read on the first. Wrap it in UseMemo. - REACTOR_POOL_001: the page surface set MinHeight via .Set(...), which is reset when the element returns to the pool, so the tab content fill could be lost on re-render. Use the .MinHeight() modifier instead. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1
|
Thanks for the review @DinahK-2SO - all seven comments are addressed and replied to inline. Summary:
Two things changed since you last looked that are worth a glance: The templates are now marked The UI now matches the XAML templates much more closely - same type ramp, backdrops, title bar layout and page surfaces, so the two sets are comparable side by side. All four also build warning-free under Reactor's analyzers, which caught a couple of real issues along the way (including missing accessible names on the MVU counter buttons). Where the templates still had to work around gaps in Reactor itself, I filed those upstream so they can be cleaned up later rather than lingering here: microsoft/microsoft-ui-reactor#914, #915, #916, #917. |
The Reactor manifests hardcoded EntryPoint=Windows.FullTrustApplication while every XAML template uses the $targetentrypoint$ token. The token already resolves to Windows.FullTrustApplication for these projects, so the generated AppxManifest.xml is unchanged - this just removes an unexplained difference between the two sets of templates. The four Reactor manifests are now byte-identical to their XAML counterparts. Verified: all four scaffold, build warning-free, generate the same EntryPoint=Windows.FullTrustApplication, and launch with package identity. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1
|
/azp run |
|
Azure Pipelines: Successfully started running 2 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. |

Summary
Adds four Reactor (
Microsoft.UI.Reactor) project templates to the existingMicrosoft.WindowsAppSDK.WinUI.CSharp.Templatesdotnet newpack, mirroring the WinUI templates from #6407 but for Reactor's declarative, pure-C# (no XAML) model.reactor,reactor-blankreactor-mvuUseReducerreactor-navviewNavigationViewshell with multiple pagesreactor-tabviewTabViewshell with multiple tabsWhat changed
dev/Templates/templates.props— four new rows in theDotnetNewOnlyProjectTemplateslot (dotnet-new only, no VSIX). Reactor apps run unpackaged, so there is noPackage.appxmanifest(RenameManifestFromleft unset). This reuses the repo's existing single-source-of-truth pack pipeline.dev/Templates/Source/ProjectTemplates/Desktop/CSharp/Reactor*— the app sources: a sharedProjectTemplate.csproj(referencesMicrosoft.UI.Reactor+Microsoft.WindowsAppSDK,WindowsAppSDKSelfContained, Debug-only Reactor devtools), a single-fileApp.csper pattern, andProperties/launchSettings.json(default + Devtools F5 profiles).dev/Templates/Dotnet/templates/reactor-*— the.template.configfor each (template.json,dotnetcli.host.json,ide.host.json,icon.png). Defaults: Reactor0.1.0-preview.12, Windows App SDK2.1.3,net10.0; overridable via--reactor-version/--wasdk-version.dev/Templates/Dotnet/README.md— documents the new Reactor templates.dev/Templates/Dotnet/Test-DotnetNewTemplates.ps1— adds the four to the scaffold/build validation loop.Validation
Validated end-to-end against the live
Microsoft.UI.Reactor 0.1.0-preview.12:dotnet pack→dotnet new install→ all four register →dotnet new→dotnet build(Debug + Release) →dotnet run. All four launch cleanly, including the title-bar app-mark icon (which relies on theIconResolverfix from microsoft/microsoft-ui-reactor#855, shipped in preview.12).A Microsoft employee must use
/azp runto validate using the PR pipelines.