# Ui Fluentui React

> Best practices for building business applications with Fluent UI React v9 (@fluentui/react-components). Covers FluentProvider setup, theming, styling with makeStyles, layout patterns, data tables, forms, dialogs, drawers, navigation, toast notifications, command bars, record forms, lookup fields, subgrids, timelines, BPF bars, app shell navigation, and accessible component composition. Triggers o…

- **Type:** Skill
- **Install:** `agentstack add skill-ryanmakesandbreaksstuff-custom-codex-claude-plugins-and-skills-ui-fluentui-react`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [RyanMakesAndBreaksStuff](https://agentstack.voostack.com/s/ryanmakesandbreaksstuff)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [RyanMakesAndBreaksStuff](https://github.com/RyanMakesAndBreaksStuff)
- **Source:** https://github.com/RyanMakesAndBreaksStuff/Custom-Codex-Claude-Plugins-and-Skills/tree/main/power-platform-full-stack-skills-v2(No longer copilot only)/skills/ui-fluentui-react

## Install

```sh
agentstack add skill-ryanmakesandbreaksstuff-custom-codex-claude-plugins-and-skills-ui-fluentui-react
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Fluent UI React v9 — Business App Patterns

You are an expert in building business/enterprise React applications with **Fluent UI v9** (`@fluentui/react-components`). This skill covers the complete component library, styling system, theming, and composition patterns for data-driven line-of-business apps.

> **Version note:** This skill targets Fluent UI React **v9** only — the `@fluentui/react-components` package. Do NOT use patterns from v8 (`@fluentui/react`) or v0 (`@fluentui/react-northstar`). Those are legacy.

---

## Resources

Component templates and code patterns are in the `resources/` folder:

| Resource | Content |
|---|---|
| `resources/pattern-mandatory-scaffold.md` | **START HERE** — Required shell components, dependencies, main.tsx/App.tsx/index.css structure, verification checklist |
| `resources/layout-patterns.md` | Flex column/row, responsive grid, page layout, print/skeleton/scrollbar (replaces v8 Stack) |
| `resources/pattern-list-detail.md` | List/Card view, Detail view with loading/error/empty states |
| `resources/pattern-form.md` | Form component, `` usage, `useFormValidation` hook, dirty tracking, auto-save, unsaved changes warning |
| `resources/pattern-data-grid.md` | `DataGrid` with sorting, selection, row actions |
| `resources/pattern-dialog-drawer.md` | Dialog (uncontrolled + controlled), Drawer (overlay + inline), ConfirmDialog, BulkEditDialog, AssignDialog |
| `resources/pattern-toolbar-nav.md` | Search/Filter bar, Toolbar, Toast notifications, Tabs, Breadcrumb |
| `resources/pattern-command-bar.md` | MDA-style command bar with overflow menu, split buttons, entity-specific command orchestration |
| `resources/pattern-record-form.md` | Record form with entity header, status badge, tab bar, collapsible form sections, loading skeleton |
| `resources/pattern-lookup-field.md` | Inline lookup with debounced search, Popover results, advanced lookup Dialog, `@odata.bind` |
| `resources/pattern-subgrid-timeline.md` | Subgrid on DataGrid, Timeline wall with compose area, date grouping, file attachments |
| `resources/pattern-entity-list-advanced.md` | Entity list with view selector, edit-columns/filters Drawer, inline editing, pagination, CSV export |
| `resources/pattern-bpf-bar.md` | Business Process Flow bar with stage navigation, stage details Popover, completed/current/future states |
| `resources/pattern-app-shell-nav.md` | AppShell layout, collapsible LeftNav with area switching, global search, recent/pinned items, HashRouter |
| `resources/styling-griffel.md` | `makeStyles` (Griffel) guide: `mergeClasses` rules, class composition checklist, spacing and typography token tables |
| `resources/pattern-errorboundary.md` | Full `ErrorBoundary` class component with Fluent MessageBar fallback and per-route usage |
| `resources/pattern-notifications-zustand.md` | Zustand notification store + Fluent Toaster bridge pattern for global notifications |
| `resources/lessons-learned.md` | Verification checklist + index mapping 24 lessons to their resource files |

Load the relevant resource when building a specific component type.

> **IMPORTANT:** Before writing any Fluent UI code, load `resources/lessons-learned.md` and
> apply its checklist. The detailed rules now live in the individual resource files listed in the index.

---

## Installation

```bash
npm install @fluentui/react-components
```

Optional icon packages:

```bash
npm install @fluentui/react-icons
```

---

## NON-NEGOTIABLE: Mandatory Shell Scaffold

When scaffolding a new business app, certain components and wrappers are **REQUIRED**
in the initial scaffold before any feature development begins.

> **Load `resources/pattern-mandatory-scaffold.md` FIRST when starting any new project.**
> It defines the required dependencies, shell components, `main.tsx` / `App.tsx` structure,
> and a verification checklist. Do NOT proceed to feature work until every item passes.

Key requirements (see the resource file for full templates and rules):

- **Dependencies**: `zustand` is required alongside Fluent UI, React Query, React Router
- **Shell components**: AppShell + TopBar + LeftNav (from `pattern-app-shell-nav.md`), ErrorBoundary, NotificationBridge + Zustand store, Suspense wrapper
- **TopBar**: Must include hamburger toggle, app title, and user profile display
- **LeftNav**: Must support expand/collapse with responsive auto-collapse at ≤768px
- **Theme**: Default to `webLightTheme` for business apps
- **CSS**: Include Fluent scrollbar styling in `index.css`

---

## FluentProvider — Required Root Wrapper

Every Fluent UI v9 app **must** wrap its root in `` with a theme. Without it, components render with no styling.

```tsx
import { FluentProvider, webLightTheme } from "@fluentui/react-components";

export const App = () => (
  
    {/* All app content goes here */}
  
);
```

**Rules:**

- Place `FluentProvider` as high as possible in the component tree (usually in `App.tsx` or `main.tsx`)
- You can nest multiple `FluentProvider` instances to override theme for a subtree (e.g., dark sidebar)
- **Default to `webLightTheme`** for business/enterprise apps — this is the standard
- Available built-in themes: `webLightTheme`, `webDarkTheme`
- For Teams apps: `teamsLightTheme`, `teamsDarkTheme`, `teamsHighContrastTheme`

### FluentProvider Height Chain

`` renders a wrapper `` with no explicit height. If your app uses
percentage-based heights (e.g., AppShell with `height: 100%`), you MUST add
`style={{ height: '100%' }}` to the FluentProvider:

```tsx
// main.tsx

  

```

**Why:** Without this, the height chain breaks:
`html (100%) → body (100%) → #root (100%) → FluentProvider (auto ← BREAK) → AppShell (100% of auto = 0)`

This causes content overflow, invisible footers/pagination, and broken scroll containers.

### Custom Theme Tokens

```tsx
import { webLightTheme, type Theme } from "@fluentui/react-components";

const customTheme: Theme = {
  ...webLightTheme,
  colorBrandBackground: "#0078d4",
  colorBrandBackgroundHover: "#106ebe",
  colorNeutralForeground1: "#242424",
};
```

Use semantic token names from the theme throughout your app — never hardcode colors.

### Dark Mode Toggle — Required

Every Fluent UI app MUST include a dark mode toggle. Use `webLightTheme` / `webDarkTheme`
and respect `prefers-color-scheme` as the initial default:

```tsx
import { webLightTheme, webDarkTheme } from "@fluentui/react-components";

const [isDark, setIsDark] = useState(
  () => window.matchMedia("(prefers-color-scheme: dark)").matches
);

```

Add a toggle in the TopBar and persist the preference to `localStorage`.

---

See `resources/styling-griffel.md` for the complete Griffel styling guide: `makeStyles` usage,
`mergeClasses` rules, class composition checklist, spacing and typography token tables.

---

## Buttons — Choosing the Right Variant

| Appearance | Use For | Example |
|---|---|---|
| `"primary"` | Main action per page/section (1 per group) | Save, Submit, Create |
| `"secondary"` | Supporting actions | Cancel, Back |
| `"subtle"` | Inline or low-emphasis actions, icon buttons | Edit, Delete in a row |
| `"transparent"` | Ghost buttons, navigation links | Breadcrumbs, inline links |
| `"outline"` | Medium emphasis, secondary CTA | Export, Filter |

```tsx
Save
Cancel
} aria-label="Edit" />
```

**Compound button** for actions with a description:

```tsx

  New Project

```

---

## Icons

Use `@fluentui/react-icons`. All icons follow the naming pattern: `{Name}{Size}{Style}`.

```tsx
import { AddRegular, EditRegular, DeleteRegular, SearchRegular } from "@fluentui/react-icons";

}>Add
} appearance="subtle" aria-label="Delete" />
```

**Sizing:** Icons default to 20px. For other sizes import the sized variant: `Add16Regular`, `Add24Regular`, `Add28Regular`.

**Styles:** `Regular` (outline) for most UI, `Filled` for selected/active states.

---

## Accessibility Checklist

- **Always provide `aria-label`** on icon-only buttons
- Use `` for all form controls — it generates correct `` associations
- Use semantic `intent` on `MessageBar` (`"error"`, `"warning"`, `"success"`, `"info"`)
- Use `useId()` hook for generating unique IDs — never hardcode IDs
- Keyboard navigation works out of the box for Fluent components — do not override `tabIndex` unless necessary
- Test with screen readers: `DataGrid` already implements ARIA grid patterns
- Use `role="status"` or `aria-live="polite"` for dynamic content updates

### Scrollable Container Accessibility

Any container with `overflow: auto` or `overflow: scroll` MUST be keyboard-accessible:

```tsx

  {/* Scrollable content */}

```

Without `tabIndex={0}`, keyboard users cannot scroll the content with arrow keys or Page Up/Down.

```tsx
import { useId } from "@fluentui/react-components";

const MyComponent = () => {
  const inputId = useId("input");
  // inputId is guaranteed unique, e.g. "input-1", "input-2"
};
```

---

## Pattern Checklist for Every Business Component

1. **Loading state** — Show ``
2. **Error state** — Show `...`
3. **Empty state** — Show `No items found.` or a custom empty illustration
4. **Disabled state** — Disable buttons during mutations with `disabled={isPending}`
5. **Validation** — Use `` for inline form errors
6. **Confirmation** — Use `` before destructive actions (delete, discard changes)
7. **Feedback** — Use toast notifications for success/failure of async operations
8. **Responsive** — Use `makeStyles` with CSS grid/flex and `@media` queries for different viewports

---

See `resources/pattern-errorboundary.md` for the full `ErrorBoundary` class component with
Fluent MessageBar fallback and per-route usage pattern.

---

## flexShrink in Flex Containers

When building page layouts with `display: flex` and `overflow: auto`, set `flexShrink: 0`
on ALL fixed-height children (headers, footers, toolbars, pagination):

```tsx
const useStyles = makeStyles({
  page: {
    display: 'flex',
    flexDirection: 'column',
    height: '100%',
    overflow: 'auto',       // Scroll container
  },
  header: {
    flexShrink: 0,           // Don't compress when viewport is small
  },
  content: {
    flex: 1,
    minHeight: 0,            // Allow flex child to shrink below content size
    overflow: 'auto',        // Inner scroll if needed
  },
  footer: {
    flexShrink: 0,           // Don't compress
  },
});
```

**IMPORTANT:** When adding `flexShrink: 0` to fix a page, grep for ALL pages that use the
same layout pattern and fix them all. Don't fix one page and leave the others vulnerable.

---

## DataGrid Responsive Patterns

Always configure explicit column sizing to prevent columns from collapsing at narrow viewports:

```tsx
const columnSizingOptions: TableColumnSizingOptions = {
  title: { minWidth: 200, idealWidth: 300 },
  status: { minWidth: 100, idealWidth: 120 },
  date: { minWidth: 100, idealWidth: 140 },
};

```

Use `` to handle overflow text instead of letting cells wrap and expand.

---

See `resources/pattern-notifications-zustand.md` for the complete Zustand notification store
and Fluent Toaster bridge pattern.

---

## Lazy Loading Pages

Use `React.lazy()` and `` for route-level code splitting. This keeps the initial bundle small.

```tsx
import { lazy, Suspense } from "react";
import { Spinner } from "@fluentui/react-components";

const AccountsPage = lazy(() => import("./pages/AccountsPage"));
const ContactsPage = lazy(() => import("./pages/ContactsPage"));

const PageFallback = () => (
  
    
  
);

// In Routes:
}>
  
    } />
    } />
  

```

**Rules:**

- Pages must use `export default` for `lazy()` to work
- Place `` around ``, not around each individual ``
- Use `` as fallback — not a blank screen

---

## HashRouter for Power Apps Code Apps

Power Apps Code Apps run inside an iframe where the host controls the URL. `BrowserRouter` will not work — always use `HashRouter`.

```tsx
import { HashRouter } from "react-router-dom";

// In main.tsx or App.tsx:

  

```

---

## Status & Option Set Color Config

Map Dataverse option set values to Fluent UI Badge colors using a config object — avoid scattered switch/if chains.

```tsx
// src/config/statusConfig.ts
import type { BadgeProps } from "@fluentui/react-components";

interface StatusConfig {
  label: string;
  color: BadgeProps["color"];
  icon?: React.ReactElement;
}

export const caseStatusConfig: Record = {
  0: { label: "Active", color: "success" },
  1: { label: "Resolved", color: "informative" },
  2: { label: "Cancelled", color: "danger" },
};

export const priorityConfig: Record = {
  1: { label: "High", color: "danger" },
  2: { label: "Normal", color: "warning" },
  3: { label: "Low", color: "informative" },
};
```

```tsx
// Usage in a component:
import { Badge } from "@fluentui/react-components";
import { caseStatusConfig } from "../config/statusConfig";

const StatusBadge = ({ statusCode }: { statusCode: number }) => {
  const config = caseStatusConfig[statusCode] ?? {
    label: "Unknown",
    color: "informative" as const,
  };
  return (
    
      {config.label}
    
  );
};
```

---

## QueryClient Configuration

Configure TanStack Query's `QueryClient` with sensible defaults for business apps.

```tsx
import { QueryClient } from "@tanstack/react-query";

export const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5 * 60 * 1000,     // 5 minutes
      gcTime: 10 * 60 * 1000,        // 10 minutes (formerly cacheTime)
      retry: 1,
      refetchOnWindowFocus: false,    // avoid surprising refetches in MDA-style apps
    },
    mutations: {
      retry: 0,
    },
  },
});
```

**Rules:**

- `staleTime` prevents constant re-fetches while the user navigates between tabs/pages
- `refetchOnWindowFocus: false` is recommended for Power Apps (the host iframe causes spurious focus events)
- Set `gcTime` >= `staleTime` so cached data isn't garbage-collected while still considered fresh

---

## Validation Checklist

After implementing a component, verify: `npm run build` passes with no errors, no `mergeClasses()` warnings appear in the browser console, the component renders inside ``, and keyboard navigation works for interactive elements.

## Common Mistakes to Avoid

| Mistake | Correct Approach |
|---|---|
| Using `Stack` from v8 | Use `makeStyles` with `display: "flex"` and `gap` |
| Hardcoded colors (`"#0078d4"`) | Use `tokens.colorBrandBackground` |
| Hardcoded spacing (`"16px"`, `paddingBottom: "40px"`) | Use `tokens.spacingVerticalL` — hardcoded px values are workarounds |
| Hardcoded radii, font sizes, shadows | Use `tokens.borderRadiusMedium`, `tokens.fontSizeBase300`, etc. |
| Missing `FluentProvider` | Wrap app root with `` |
| Using `style={{...}}` inline | Use `makeStyles` for performance and consistency |
| Reading `event.target.value` in onChange | Read from second arg: `(_, data) => data.value` |
| Not wrapping inputs in `` | Always use `` for accessible forms |
| v8 `DetailsList` for tables | Use v9 `DataGrid` with `createTableColumn` |
| v8 `Modal` for dialogs | Use v9 `Dialog` + `DialogSurface` |
| v8 `Panel` for side panels | Use v9 `Drawer` with `position="end"` |
| Using `@fluentui/react` (v8 package) | Use `@fluentui/react-components` (v9) |
| Importing from `@fluentui/react-northstar` | Deprecated — use `@fluentui/react-components` |
| Missing `aria-label` on icon buttons | Always add `aria-label="Action name"` |
| `BrowserRouter` in Power Apps | Use `HashRouter` — host controls URL |
| Hardcoded status colors | Use a status config map with `Badge` `color` prop |
| Custom dropdown for nav areas | Use Fluent `Menu` / `MenuList` |
| Custom HTML table for data | Use Fluent `DataGrid` with `createTableColumn` |
| Hardcoded back-navigation (`navigate("/list")`) | Pass `{ state: { from } }` via React Router and read it in the detail page — back should return to the page the user came from, not a hardcoded route |

---

## Package Reference

| Package | Purpose |
|---|---|
| `@fluentui/react-components` | Main v9

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [RyanMakesAndBreaksStuff](https://github.com/RyanMakesAndBreaksStuff)
- **Source:** [RyanMakesAndBreaksStuff/Custom-Codex-Claude-Plugins-and-Skills](https://github.com/RyanMakesAndBreaksStuff/Custom-Codex-Claude-Plugins-and-Skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-ryanmakesandbreaksstuff-custom-codex-claude-plugins-and-skills-ui-fluentui-react
- Seller: https://agentstack.voostack.com/s/ryanmakesandbreaksstuff
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
