Skip to main content

fluentui-blazor-usage

Provides accurate coding patterns for building Blazor applications with the Microsoft.FluentUI.AspNetCore.Components v5 NuGet package. Covers service registration, theming (CSS-based, no FluentDesignTheme), layout, navigation, dialogs, data grid, forms, icons, and common pitfalls.

설치로 이동

소스 정보

저장소
markheydon/billdrift-web
최근 소스 활동
2026년 7월 1일 22:25
감지된 SKILL.md 언어
영어
스타
0
포크
0

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
4 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
fluentui-blazor-usage
description
Provides accurate coding patterns for building Blazor applications with the Microsoft.FluentUI.AspNetCore.Components v5 NuGet package. Covers service registration, theming (CSS-based, no FluentDesignTheme), layout, navigation, dialogs, data grid, forms, icons, and common pitfalls.
# Fluent UI Blazor v5 — Usage Skill This skill helps AI assistants generate **correct, idiomatic code** for applications that consume the `Microsoft.FluentUI.AspNetCore.Components` **v5** NuGet package. v5 targets **.NET 9+** and wraps `@fluentui/web-components` v3. > **Critical**: v5 is a major rewrite. Many v4 APIs are removed or renamed. > Always verify patterns against this skill before answering. --- ## Quick Setup Checklist ```csharp // Program.cs builder.Services.AddFluentUIComponents(); ``` ```razor @* App.razor / MainLayout.razor — add providers once at root *@ <FluentProviders /> ``` ```html <!-- index.html / _Host.cshtml — required CSS & JS --> <link href="_content/Microsoft.FluentUI.AspNetCore.Components/css/default-fuib.css" rel="stylesheet" /> ``` The `<FluentProviders />` component replaces the need to manually add `<FluentDialogProvider />`, `<FluentTooltipProvider />`, and `<FluentKeyCodeProvider />` separately. --- ## Key v5 Differences from v4 | Area | v4 | v5 | |---|---|---| | Target framework | net8.0 | net9.0 / net10.0 | | Theming | `<FluentDesignTheme>` component | CSS custom properties via JS (`setTheme`), `body[data-theme]` attribute | | Toast / MessageBar | `IToastService`, `IMessageService` | **Removed** — use `FluentToast` component directly or custom solution | | Navigation | `FluentNavMenu`, `FluentNavLink`, `FluentNavGroup` | `FluentNav`, `FluentNavItem`, `FluentNavCategory`, `FluentNavSectionHeader` | | Dialog API | `IDialogContentComponent<T>`, complex reference | Simplified: `IDialogService.ShowDialogAsync<TDialog>(DialogOptions)` | | List binding | `FluentListBase<TOption>`, `SelectedOptions` | `FluentListBase<TOption, TValue>`, `SelectedItems` | | Progress | `FluentProgress` | `FluentProgressBar` (`FluentProgress` = obsolete shim) | | Appearance enum | `Appearance.Accent`, `.Stealth`, etc. | `ButtonAppearance.Primary`, `.Transparent`, etc. | | Switch | `CheckedMessage`/`UncheckedMessage` child content | Removed — label only via `Label` parameter | | Component base | Property injection | Constructor injection of `LibraryConfiguration` | | Margin / Padding | Not on components | Available on **every** component via `Margin` and `Padding` parameters | | Icons packages | Separate NuGet packages | Bundled (core icons), with optional extended packages | --- ## Theming v5 replaces `<FluentDesignTheme>` with a **JavaScript + CSS custom property** model. ### Apply a theme ```razor @inject IJSRuntime JSRuntime <FluentButton OnClick="@SwitchTheme">Toggle theme</FluentButton> @code { private async Task SwitchTheme() { await JSRuntime.InvokeVoidAsync("Blazor.theme.switchTheme"); } } ``` ### Detect current mode ```javascript // body[data-theme="dark"] → dark mode // body without data-theme → light mode Blazor.theme.isDarkMode() // returns boolean Blazor.theme.isSystemDark() // returns boolean ``` ### Conditional rendering by theme ```razor <FluentIcon Class="hidden-if-light" Value="@(new Icons.Filled.Size20.WeatherSunny())" /> <FluentIcon Class="hidden-if-dark" Value="@(new Icons.Filled.Size20.WeatherMoon())" /> ``` ### CSS variables All Fluent design tokens are available as CSS custom properties: `var(--colorBrandBackground)`, `var(--colorNeutralForeground1)`, `var(--fontSizeBase300)`, `var(--borderRadiusMedium)`, etc. C# constants are available via `StylesVariables` and `SystemColors`: ```csharp // In component styles style="@($"background: {SystemColors.Neutral.Background1}")" // Equivalent to: background: var(--colorNeutralBackground1); style="@($"border-radius: {StylesVariables.Borders.Radius.Medium}")" // Equivalent to: border-radius: var(--borderRadiusMedium); ``` --- ## Layout & Navigation ### FluentLayout ```razor <FluentLayout> <FluentLayoutItem Area="LayoutArea.Header"> <FluentLayoutHamburger /> <span>My App</span> </FluentLayoutItem> <FluentLayoutItem Area="LayoutArea.Menu"> <FluentNav> <FluentNavItem Href="/" Icon="@(new Icons.Regular.Size20.Home())"> Home </FluentNavItem> <FluentNavCategory Label="Settings" Icon="@(new Icons.Regular.Size20.Settings())"> <FluentNavItem Href="/settings/profile">Profile</FluentNavItem> <FluentNavItem Href="/settings/account">Account</FluentNavItem> </FluentNavCategory> <FluentNavSectionHeader Label="Admin" /> <FluentNavItem Href="/admin">Dashboard</FluentNavItem> </FluentNav> </FluentLayoutItem> <FluentLayoutItem Area="LayoutArea.Content"> @Body </FluentLayoutItem> <FluentLayoutItem Area="LayoutArea.Footer"> <span>&copy; 2025</span> </FluentLayoutItem> </FluentLayout> ``` > **Common mistake**: Using `FluentNavMenu` / `FluentNavLink` / `FluentNavGroup` (v4 names). These do **not** exist in v5. --- ## Dialogs ### Show a simple dialog ```csharp @inject IDialogService DialogService private async Task OpenDialog() { var options = new DialogOptions { Header = { Title = "Confirm action" }, Size = DialogSize.Medium, Modal = true, }; var result = await DialogService.ShowDialogAsync<ConfirmDialog>(options); if (!result.Cancelled) { // result.Value contains the returned data } } ``` ### Dialog component ```razor @* ConfirmDialog.razor *@ <p>Are you sure you want to proceed?</p> <FluentButton Appearance="ButtonAppearance.Primary" OnClick="@Confirm">Yes</FluentButton> <FluentButton OnClick="@Cancel">No</FluentButton> @code { [CascadingParameter] public IDialogInstance Dialog { get; set; } = default!; private async Task Confirm() => await Dialog.CloseAsync(DialogResult.Ok(true)); private async Task Cancel() => await Dialog.CloseAsync(DialogResult.Cancel()); } ``` ### Show a drawer ```csharp var result = await DialogService.ShowDrawerAsync<DrawerContent>(options => { options.Header.Title = "Settings"; options.Alignment = DialogAlignment.End; options.Size = DialogSize.Small; }); ``` ### Pass parameters to the dialog component ```csharp var options = new DialogOptions { Header = { Title = "Edit item" }, Parameters = new Dictionary<string, object?> { ["ItemId"] = selectedItemId, ["ItemName"] = selectedItemName, }, }; await DialogService.ShowDialogAsync<EditDialog>(options); ``` > **Common mistake**: Implementing `IDialogContentComponent<T>` (v4 pattern). In v5, dialog components are plain Razor components that receive `IDialogInstance` as a cascading parameter. --- ## Data Grid ```razor <FluentDataGrid Items="@people" Pagination="@pagination"> <PropertyColumn Property="@(p => p.Name)" Sortable="true" /> <PropertyColumn Property="@(p => p.Email)" /> <TemplateColumn Title="Actions"> <FluentButton Size="ButtonSize.Small" OnClick="@(() => Edit(context))"> Edit </FluentButton> </TemplateColumn> </FluentDataGrid> <FluentPaginator State="@pagination" /> @code { private IQueryable<Person> people = GetPeople().AsQueryable(); private PaginationState pagination = new() { ItemsPerPage = 10 }; } ``` ### Remote data with ItemsProvider ```csharp <FluentDataGrid ItemsProvider="@dataProvider" Virtualize="true" ItemSize="46"> <PropertyColumn Property="@(p => p.Name)" Sortable="true" /> </FluentDataGrid> @code { private GridItemsProvider<Person> dataProvider = default!; protected override void OnInitialized() { dataProvider = async request => { var result = await Http.GetFromJsonAsync<PagedResult<Person>>( $"api/people?start={request.StartIndex}&count={request.Count}"); return GridItemsProviderResult.From(result!.Items, result.TotalCount); }; } } ``` See [DATAGRID.md](references/DATAGRID.md) for advanced patterns (EF adapter, OData, column options, resize, custom sort). --- ## Forms & Input Components v5 input components extend `InputBase<TValue>` and implement `IFluentField`, providing built-in form validation integration. ```razor <EditForm Model="@model" OnValidSubmit="@Submit"> <DataAnnotationsValidator /> <FluentTextField @bind-Value="model.Name" Label="Name" Required="true" /> <FluentNumberField @bind-Value="model.Age" Label="Age" Min="0" Max="150" /> <FluentSelect TOption="string" TValue="string" Items="@countries" @bind-Value="model.Country" OptionText="@(c => c)" OptionValue="@(c => c)" Label="Country" /> <FluentCheckbox @bind-Value="model.AcceptTerms" Label="I accept the terms" /> <FluentButton Type="ButtonType.Submit" Appearance="ButtonAppearance.Primary"> Submit </FluentButton> </EditForm> ``` ### List components — two type parameters All list-based components (`FluentSelect`, `FluentCombobox`, `FluentListbox`) now take **two** type parameters: `TOption` (the item type) and `TValue` (the bound value type). ```razor <FluentSelect TOption="Country" TValue="int" Items="@countries" @bind-Value="model.CountryId" OptionText="@(c => c.Name)" OptionValue="@(c => c.Id)" Label="Country" /> @* Multiple selection *@ <FluentListbox TOption="string" TValue="string" Items="@tags" Multiple="true" SelectedItems="@selectedTags" SelectedItemsChanged="@(items => selectedTags = items)" OptionText="@(t => t)" OptionValue="@(t => t)" /> ``` > **Common mistake**: Using `SelectedOptions` or `SelectedOptionsChanged` (v4 names). In v5, use `SelectedItems` / `SelectedItemsChanged`. --- ## Icons Icons are instantiated as objects and passed via `Value`, `IconStart`, or `IconEnd` parameters: ```razor @* Standalone icon *@ <FluentIcon Value="@(new Icons.Regular.Size24.Add())" /> @* Icon with color *@ <FluentIcon Value="@(new Icons.Filled.Size20.Heart().WithColor("red"))" /> @* Icon in a button *@ <FluentButton IconStart="@(new Icons.Regular.Size20.Add())" Appearance="ButtonAppearance.Primary"> Add item </FluentButton> @* Icon from image URL *@ <FluentIcon Value="@Icon.FromImageUrl("/images/logo.png")" /> ``` Icon naming: `Icons.{Variant}.{Size}.{Name}` - Variants: `Regular`, `Filled` - Sizes: `Size16`, `Size20`, `Size24`, `Size28`, `Size32`, `Size48` --- ## Margin & Padding (NEW in v5) Every component supports `Margin` and `Padding` parameters using a spacing-utility syntax: ```razor <FluentCard Margin="Margin.All4" Padding="Padding.Horizontal3 Padding.Vertical2"> Content with spacing </FluentCard> ``` --- ## Common Pitfalls
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기