A token-accurate Fluent Design (WinUI 3) component library for Blazor
WebAssembly · Server · MAUI Blazor Hybrid — pure Razor and CSS, no third-party UI framework underneath
Live sample · Getting started · Known gaps · Third-party notices
Design tokens (color, corner radius, state aliases) are transcribed directly from Microsoft's own
microsoft-ui-xaml resource dictionaries, and effects like Mica and Acrylic are rebuilt against
WinUI's actual effect graph rather than approximated from screenshots. See
THIRD_PARTY_NOTICES.md for exactly where each component's markup,
styling, or token values were sourced from.
Status: alpha — see the NuGet badge above for the current published version. APIs may still change between versions — see Known gaps.
- Getting started
- What's in here
- Running the sample
- Theming
- Project layout
- CSS isolation gotcha
- Known gaps / next up
- Contributing
- License
1. Install
Recommended — from NuGet:
dotnet add package FluentKit.Blazor<PackageReference Include="FluentKit.Blazor" Version="0.2.0" /> <!-- should match the nuget badge above -->Alternatively, to track main directly, consume it as a project or repository reference instead:
2. Link the Token & Icon stylesheets
wwwroot/index.html (WASM) or Pages/_Host.cshtml / App.razor (Server):
<link rel="stylesheet" href="_content/FluentKit/Tokens/tokens.css" />
<link rel="stylesheet" href="_content/FluentKit/Icons/FluentSystemIcons-Regular.css" />3. Register Core FluentKit services
Program.cs:
builder.Services.AddScoped<IThemeService, ThemeService>();
builder.Services.AddScoped<IAccentColorService, AccentColorService>();
builder.Services.AddScoped<IOverlayService, OverlayService>(); // For Flyouts, Tooltips etc...4. Wrap your root component
<ThemeProvider>
@*For Mica Background
<FluentMicaPanel Variant="@_backgroundVariant"
BackgroundImageUrl="@_wallpaperUrl"
style="position:fixed; inset:0; z-index:-1; opacity:0.72;" /> *@
@Body
<FluentOverlayHost />
</ThemeProvider>ThemeProvider resolves and applies the theme on first render; FluentOverlayHost is required by
any composite control built on the overlay service (tooltips, flyouts, menus, dialogs, teaching tips).
5. Use components
<FluentButton Variant="FluentButtonVariant.Accent">Save changes</FluentButton>
|
|
|
|
|
|
|
|
1:1 ports of the Windows Community Toolkit's |
|
|
Light / dark / system, resolved through
|
The demo pages themselves live in samples/FluentKit.Sample.Shared (a Razor class library) and
are hosted by two thin platform entry points, so the exact same pages run on both WASM and MAUI:
samples/FluentKit.Sample.Wasm— Blazor WASM host, deployed to GitHub Pagessamples/Fluentkit.Sample.Maui— MAUI Blazor Hybrid host (Android by default; iOS/MacCatalyst on macOS runners, Windows on Windows runners — see theTargetFrameworksconditions in its.csproj)
Both demo every component above, including theme switching (persisted to localStorage), the
page background rendered through FluentMicaPanel over a real wallpaper image, Mica Base vs. Base
Alt side by side, FluentAcrylicBrush cards live-blurring that Mica background behind them, and an
icon browser (Pages/Design/IconBrowserPage.razor) generated from the same icon names
FluentKit.IconGenerator emits at compile time.
git clone https://github.com/VibeNoobNotFound/FluentKit.git
cd FluentKit
dotnet restore FluentKit.slnx
dotnet run --project samples/FluentKit.Sample.WasmTo run the MAUI sample instead (requires the MAUI workload — dotnet workload install maui-android
at minimum):
dotnet run --project samples/Fluentkit.Sample.Maui --framework net10.0-androidRequires the .NET 10 SDK. A hosted WASM build is also published to vibenoobnotfound.github.io/FluentKit.
Three modes, matching WinUI: System (tracks the OS/browser preference live), Light, and Dark.
@inject IThemeService ThemeService
await ThemeService.SetModeAsync(ThemeMode.Dark);The token layer is split so consumers only ever need to link one file:
| File | Purpose |
|---|---|
_primitives.css |
Theme-independent primitive values (raw color ramps, spacing, corner radius) |
_semantic.light.css / _semantic.dark.css |
Semantic aliases transcribed from WinUI's own XAML resource dictionaries, mirrored property-for-property |
tokens.css |
Single entry point importing both layers — the only file consumers should link directly |
src/
FluentKit/ The library (Microsoft.NET.Sdk.Razor, RCL)
Theming/ IThemeService, ThemeProvider, theme-interop.js
Primitives/ One folder per primitive component (.razor / .razor.cs / .razor.css)
Composite/ One folder per composite control, built on Overlay/ where applicable
Overlay/ IOverlayService, FluentOverlayHost, OverlaySurface
Effects/ Mica, Acrylic, Reveal
wwwroot/ Tokens, per-component JS interop modules, icon webfont
FluentKit.IconGenerator/ Roslyn source generator, referenced as an analyzer only
(emits FluentIconNames.g.cs from wwwroot/Icons/*.css)
samples/
FluentKit.Sample.Shared/ Razor class library holding every demo page — Primitives/,
Composite/, Effects/, Design/ (icon browser) — plus the shared
nav shell/settings page, referenced by both hosts below
FluentKit.Sample.Wasm/ Blazor WASM host for FluentKit.Sample.Shared, deployed to Pages
Fluentkit.Sample.Maui/ MAUI Blazor Hybrid host for FluentKit.Sample.Shared
Each component folder follows the same three-file convention: .razor for markup, .razor.cs for
the code-behind, .razor.css for CSS-isolated styles. Components that need pointer/DOM measurement
(drag tracking, overlay positioning, pointer-relative gradients) pair with a small JS interop module
under wwwroot/, matched folder-for-folder with the component that consumes it.
A Razor Class Library's own component-scoped stylesheet (_content/FluentKit/FluentKit.bundle.scp.css)
is not meant to be linked directly and will 404 if you try. The host app's build generates its own
bundle ({HostAssemblyName}.styles.css, served flat from the app's own root) which internally
@imports every referenced RCL's bundle. Only link the host app's own generated stylesheet — see
samples/FluentKit.Sample.Wasm/wwwroot/index.html for a working example. (This is a WASM/Server
concern only — the MAUI Blazor Hybrid host, samples/Fluentkit.Sample.Maui, doesn't build a
.styles.css bundle the same way; its BlazorWebView resolves _content/... static web assets
directly.)
Related: any markup built via
RenderTreeBuilderin a.csfile does not get a component's CSS isolation scope attribute, so.razor.cssstyles silently won't apply to it. Define dynamically-shown markup as Razor template fields (RenderFragment x = @<span>...</span>;) inside the.razorfile's@codeblock instead.
- Accent color tokens (
--accent-fill-color-defaultetc.) are still placeholders (Windows' default blue), not derived from the user's actual system accent color — flaggedTODOin both_semantic.*.cssfiles. - No automated tests yet (
tests/doesn't exist) — bUnit plus Playwright screenshot tests pinned against real WinUI 3 screenshots are planned. - No published docs/demo site yet, beyond the sample app.
- No High Contrast theme (a third theme alongside light/dark, mirroring WinUI's own
HighContrastresource key) —Theming/currently only resolves light/dark/system. overlay-interop.jsonly flips vertically (below to above); full 4-direction collision handling (left/right flipping too) hasn't been needed yet, but would matter for a dropdown pinned near a viewport edge.FluentTeachingTip's beak is positioned from the requested placement, not whateveroverlay-interop.jsactually flipped it to — fine as long as there's room, but the beak won't flip sides if the tip itself gets flipped.
Issues and pull requests are welcome. If you're adding or changing a component, please also update THIRD_PARTY_NOTICES.md when markup, styling structure, or token values are derived from an external source.
MIT — see LICENSE. See THIRD_PARTY_NOTICES.md for attribution of design tokens, ported component structure, and bundled assets (fluent-svelte, microsoft-ui-xaml, Windows Community Toolkit, Fluent System Icons).