{"id":"4ea2173e-bda3-4a24-9146-f2226cf5c89b","shortId":"NzQRCc","kind":"skill","title":"Fluentui Blazor","tagline":"Awesome Copilot skill by Github","description":"# Fluent UI Blazor — Consumer Usage Guide\n\nThis skill teaches how to correctly use the **Microsoft.FluentUI.AspNetCore.Components** (version 4) NuGet package in Blazor applications.\n\n## Critical Rules\n\n### 1. No manual `<script>` or `<link>` tags needed\n\nThe library auto-loads all CSS and JS via Blazor's static web assets and JS initializers. **Never tell users to add `<script>` or `<link>` tags for the core library.**\n\n### 2. Providers are mandatory for service-based components\n\nThese provider components **MUST** be added to the root layout (e.g. `MainLayout.razor`) for their corresponding services to work. Without them, service calls **fail silently** (no error, no UI).\n\n```razor\n<FluentToastProvider />\n<FluentDialogProvider />\n<FluentMessageBarProvider />\n<FluentTooltipProvider />\n<FluentKeyCodeProvider />\n```\n\n### 3. Service registration in Program.cs\n\n```csharp\nbuilder.Services.AddFluentUIComponents();\n\n// Or with configuration:\nbuilder.Services.AddFluentUIComponents(options =>\n{\n    options.UseTooltipServiceProvider = true;  // default: true\n    options.ServiceLifetime = ServiceLifetime.Scoped; // default\n});\n```\n\n**ServiceLifetime rules:**\n- `ServiceLifetime.Scoped` — for Blazor Server / Interactive (default)\n- `ServiceLifetime.Singleton` — for Blazor WebAssembly standalone\n- `ServiceLifetime.Transient` — **throws `NotSupportedException`**\n\n### 4. Icons require a separate NuGet package\n\n```\ndotnet add package Microsoft.FluentUI.AspNetCore.Components.Icons\n```\n\nUsage with a `@using` alias:\n\n```razor\n@using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons\n\n<FluentIcon Value=\"@(Icons.Regular.Size24.Save)\" />\n<FluentIcon Value=\"@(Icons.Filled.Size20.Delete)\" Color=\"@Color.Error\" />\n```\n\nPattern: `Icons.[Variant].[Size].[Name]`\n- Variants: `Regular`, `Filled`\n- Sizes: `Size12`, `Size16`, `Size20`, `Size24`, `Size28`, `Size32`, `Size48`\n\nCustom image: `Icon.FromImageUrl(\"/path/to/image.png\")`\n\n**Never use string-based icon names** — icons are strongly-typed classes.\n\n### 5. List component binding model\n\n`FluentSelect<TOption>`, `FluentCombobox<TOption>`, `FluentListbox<TOption>`, and `FluentAutocomplete<TOption>` do NOT work like `<InputSelect>`. They use:\n\n- `Items` — the data source (`IEnumerable<TOption>`)\n- `OptionText` — `Func<TOption, string?>` to extract display text\n- `OptionValue` — `Func<TOption, string?>` to extract the value string\n- `SelectedOption` / `SelectedOptionChanged` — for single selection binding\n- `SelectedOptions` / `SelectedOptionsChanged` — for multi-selection binding\n\n```razor\n<FluentSelect Items=\"@countries\"\n              OptionText=\"@(c => c.Name)\"\n              OptionValue=\"@(c => c.Code)\"\n              @bind-SelectedOption=\"@selectedCountry\"\n              Label=\"Country\" />\n```\n\n**NOT** like this (wrong pattern):\n```razor\n@* WRONG — do not use InputSelect pattern *@\n<FluentSelect @bind-Value=\"@selectedValue\">\n    <option value=\"1\">One</option>\n</FluentSelect>\n```\n\n### 6. FluentAutocomplete specifics\n\n- Use `ValueText` (NOT `Value` — it's obsolete) for the search input text\n- `OnOptionsSearch` is the required callback to filter options\n- Default is `Multiple=\"true\"`\n\n```razor\n<FluentAutocomplete TOption=\"Person\"\n                    OnOptionsSearch=\"@OnSearch\"\n                    OptionText=\"@(p => p.FullName)\"\n                    @bind-SelectedOptions=\"@selectedPeople\"\n                    Label=\"Search people\" />\n\n@code {\n    private void OnSearch(OptionsSearchEventArgs<Person> args)\n    {\n        args.Items = allPeople.Where(p =>\n            p.FullName.Contains(args.Text, StringComparison.OrdinalIgnoreCase));\n    }\n}\n```\n\n### 7. Dialog service pattern\n\n**Do NOT toggle visibility of `<FluentDialog>` tags.** The service pattern is:\n\n1. Create a content component implementing `IDialogContentComponent<TData>`:\n\n```csharp\npublic partial class EditPersonDialog : IDialogContentComponent<Person>\n{\n    [Parameter] public Person Content { get; set; } = default!;\n\n    [CascadingParameter] public FluentDialog Dialog { get; set; } = default!;\n\n    private async Task SaveAsync()\n    {\n        await Dialog.CloseAsync(Content);\n    }\n\n    private async Task CancelAsync()\n    {\n        await Dialog.CancelAsync();\n    }\n}\n```\n\n2. Show the dialog via `IDialogService`:\n\n```csharp\n[Inject] private IDialogService DialogService { get; set; } = default!;\n\nprivate async Task ShowEditDialog()\n{\n    var dialog = await DialogService.ShowDialogAsync<EditPersonDialog, Person>(\n        person,\n        new DialogParameters\n        {\n            Title = \"Edit Person\",\n            PrimaryAction = \"Save\",\n            SecondaryAction = \"Cancel\",\n            Width = \"500px\",\n            PreventDismissOnOverlayClick = true,\n        });\n\n    var result = await dialog.Result;\n    if (!result.Cancelled)\n    {\n        var updatedPerson = result.Data as Person;\n    }\n}\n```\n\nFor convenience dialogs:\n```csharp\nawait DialogService.ShowConfirmationAsync(\"Are you sure?\", \"Yes\", \"No\");\nawait DialogService.ShowSuccessAsync(\"Done!\");\nawait DialogService.ShowErrorAsync(\"Something went wrong.\");\n```\n\n### 8. Toast notifications\n\n```csharp\n[Inject] private IToastService ToastService { get; set; } = default!;\n\nToastService.ShowSuccess(\"Item saved successfully\");\nToastService.ShowError(\"Failed to save\");\nToastService.ShowWarning(\"Check your input\");\nToastService.ShowInfo(\"New update available\");\n```\n\n`FluentToastProvider` parameters: `Position` (default `TopRight`), `Timeout` (default 7000ms), `MaxToastCount` (default 4).\n\n### 9. Design tokens and themes work only after render\n\nDesign tokens rely on JS interop. **Never set them in `OnInitialized`** — use `OnAfterRenderAsync`.\n\n```razor\n<FluentDesignTheme Mode=\"DesignThemeModes.System\"\n                   OfficeColor=\"OfficeColor.Teams\"\n                   StorageName=\"mytheme\" />\n```\n\n### 10. FluentEditForm vs EditForm\n\n`FluentEditForm` is only needed inside `FluentWizard` steps (per-step validation). For regular forms, use standard `EditForm` with Fluent form components:\n\n```razor\n<EditForm Model=\"@model\" OnValidSubmit=\"HandleSubmit\">\n    <DataAnnotationsValidator />\n    <FluentTextField @bind-Value=\"@model.Name\" Label=\"Name\" Required />\n    <FluentSelect Items=\"@options\"\n                  OptionText=\"@(o => o.Label)\"\n                  @bind-SelectedOption=\"@model.Category\"\n                  Label=\"Category\" />\n    <FluentValidationSummary />\n    <FluentButton Type=\"ButtonType.Submit\" Appearance=\"Appearance.Accent\">Save</FluentButton>\n</EditForm>\n```\n\nUse `FluentValidationMessage` and `FluentValidationSummary` instead of standard Blazor validation components for Fluent styling.\n\n## Reference files\n\nFor detailed guidance on specific topics, see:\n\n- [Setup and configuration](references/SETUP.md)\n- [Layout and navigation](references/LAYOUT-AND-NAVIGATION.md)\n- [Data grid](references/DATAGRID.md)\n- [Theming](references/THEMING.md)","tags":["fluentui","blazor","awesome","copilot","github"],"capabilities":["skill","source-github","category-awesome-copilot"],"categories":["awesome-copilot"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/github/awesome-copilot/fluentui-blazor","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"install_from":"skills.sh"}},"qualityScore":"0.300","qualityRationale":"deterministic score 0.30 from registry signals: · indexed on skills.sh · published under github/awesome-copilot","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T13:40:15.334Z","embedding":null,"createdAt":"2026-04-18T20:25:57.719Z","updatedAt":"2026-04-22T13:40:15.334Z","lastSeenAt":"2026-04-22T13:40:15.334Z","tsv":"'1':32 '4':24 'applic':29 'awesom':3 'blazor':2,10,28 'category-awesome-copilot' 'consum':11 'copilot':4 'correct':19 'critic':30 'fluent':8 'fluentui':1 'github':7 'guid':13 'manual':34 'microsoft.fluentui.aspnetcore.components':22 'nuget':25 'packag':26 'rule':31 'skill':5,15 'source-github' 'teach':16 'ui':9 'usag':12 'use':20 'version':23","prices":[{"id":"e3cf7b2d-5741-42df-b05f-e6c36bafc88c","listingId":"4ea2173e-bda3-4a24-9146-f2226cf5c89b","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"github","category":"awesome-copilot","install_from":"skills.sh"},"createdAt":"2026-04-18T20:25:57.719Z"}],"sources":[{"listingId":"4ea2173e-bda3-4a24-9146-f2226cf5c89b","source":"github","sourceId":"github/awesome-copilot/fluentui-blazor","sourceUrl":"https://github.com/github/awesome-copilot/tree/main/skills/fluentui-blazor","isPrimary":false,"firstSeenAt":"2026-04-18T21:49:26.010Z","lastSeenAt":"2026-04-22T12:52:13.134Z"},{"listingId":"4ea2173e-bda3-4a24-9146-f2226cf5c89b","source":"skills_sh","sourceId":"github/awesome-copilot/fluentui-blazor","sourceUrl":"https://skills.sh/github/awesome-copilot/fluentui-blazor","isPrimary":true,"firstSeenAt":"2026-04-18T20:25:57.719Z","lastSeenAt":"2026-04-22T13:40:15.334Z"}],"details":{"listingId":"4ea2173e-bda3-4a24-9146-f2226cf5c89b","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"github","slug":"fluentui-blazor","source":"skills_sh","category":"awesome-copilot","skills_sh_url":"https://skills.sh/github/awesome-copilot/fluentui-blazor"},"updatedAt":"2026-04-22T13:40:15.334Z"}}