Ask an AI coding agent for “a card component to show a list item” and watch what it actually hands back: a <div>, a hardcoded #f3f2f1 background, a manually built header row with inline flexbox styles, and a border-radius value the agent invented on the spot. Nothing about it is wrong, exactly. It renders. It isn’t Fluent UI, though — it doesn’t know your SharePoint host has a theme, and it will look subtly foreign the moment it lands next to the rest of the page.
That’s the failure mode this post is about. Generic React training data knows React. It doesn’t know that @fluentui/react-components exists as a hard constraint, that SharePoint zones resize a web part without warning, or that a “card” inside a Teams tab needs different density than a card on a full SharePoint page. Nothing in a general-purpose model’s defaults tells it any of that.
That’s the gap react-design.md closes. It’s the third of the four reference files in the SharePoint/spfx-dev-skills skill pack, and it’s a different kind of document than the ones this series has covered so far. Post 2 walked through create.md — a procedure, a sequence of flags for yo @microsoft/sharepoint. Post 4 walked through upgrade.md — also a procedure, a lifecycle of precondition checks and verification steps. react-design.md isn’t a procedure. It’s titled, verbatim, the “Copilot UI Contract v2.1,” and it reads like one: sixteen sections of MUST/SHOULD/MAY normative language governing what an agent is allowed to generate before it writes a single component.
One more thing worth knowing before the rules themselves: this skill pack is more than a maintainer’s house style. The Microsoft 365 Developer Blog post describing the pack’s evaluation methodology (“Behind SPFx Dev Skills: testing what agents know and fixing what they miss,” Waldek Mastykarz) documents repeated-run testing of an SPFx upgrade scenario — five runs each, baseline agents hitting only 37.5% configuration correctness, rising to 93.75% once the skill’s guidance was in context. That number is specific to the upgrade.md scenario covered in Post 4, not to the Fluent UI rules below — there’s no equivalent published test of react-design.md compliance. But it’s the right context to hold onto here: the pack’s authors test their guidance against real agent runs rather than publishing opinions and hoping.
Scope and Platform: One Rule Above All the Others
Before anything else, react-design.md draws a boundary around what counts as “UI” in the first place. Section 1 defines four tiers — primitive (button, input, badge), composite (toolbar, card, feed item), assembly (feed, dashboard section, form), and template (full page or multi-region flow) — and is explicit that an agent shouldn’t default to the biggest one:
Agents MUST NOT assume all requests are full-page experiences.
That matters because it’s the difference between an agent that generates a tidy Badge when you ask for a status indicator, and one that scaffolds an entire page shell because it doesn’t know any better.
Section 2 is where the contract’s single most consequential rule lives — the one that would have stopped the hand-rolled <div> card at the top of this post before it happened:
Agents MUST NOT recreate Fluent components using custom HTML/CSS.
The platform is fixed: React, TypeScript, SPFx-compatible patterns, @fluentui/react-components, @fluentui/react-icons. And there’s a version-safety clause that pairs naturally with Post 4’s upgrade discipline — the agent MUST verify the installed Fluent UI version against the project’s package.json before importing anything, matching to what’s installed rather than assuming a version the project hasn’t declared.
Theme Precedence: Accessibility First, Brand Last
Sections 4 through 6 are the part of react-design.md most SPFx developers won’t have seen written down this precisely anywhere else. Section 4 gives a strict, ordered precedence for how a generated UI should resolve competing design pressures:
- Accessibility and legibility
- Host surface integration
- SharePoint alignment
- Brand expression via tokens
Read that order carefully — brand comes last, not first. An agent is explicitly told not to hardcode colors or surfaces, and to prefer neutral, adaptive surfaces over anything fixed. Section 5 turns that into an implementation requirement: generated UI must demonstrate theme integration, must use FluentProvider when theming is relevant, must use theme-aware tokens instead of fixed colors, should accept a theme via props or context, and — for the case where nothing else is available — must fall back to Fluent’s own defaults rather than inventing a palette.
Section 6 brings SharePoint itself into the same precedence chain: respect SharePoint themes when they’re present, adapt to zones and columns and dynamic width, favor familiar patterns (cards, lists, panels, sections), and don’t assume an app-shell layout unless the request specifically calls for one.
What this means for you: if an agent-generated component ships with any hardcoded hex value in it, that’s a contract violation you can point to directly — Section 4 forbids it in plain language.
Container Context: The Same Card, Three Different Rulebooks
Section 7 is the strongest single section in the file, and the one most worth quoting directly:
Agents MUST infer context.
The same card component is governed by three distinct rule sets depending on where it’s going to render — and the contract spells out all three:
| Context | Layout rule | Density rule | Interaction rule |
|---|---|---|---|
| Inline / Conversational | MUST use single-column layout | MUST prioritize scannability; SHOULD avoid dense toolbars/forms | MUST NOT rely on hover-only interactions |
| Embedded / Web Part | SHOULD favor vertical layouts; MUST resize cleanly across zones | MUST assume constrained width; MUST use compact density; MUST minimize padding and elevation | Same accessibility baseline as elsewhere in the contract |
| Full Page | MAY use multi-column layouts | MAY introduce stronger hierarchy | No added constraint beyond the general rules |

Notice the asymmetry: inline and embedded contexts get MUST-level constraints, full page gets only MAY-level permissions. The contract is written defensively — it assumes an agent’s default instinct is to over-build, so it locks down the narrow contexts hard and only loosens up when the agent has confirmed it’s actually building for a full page.
Composition, Interaction, and the Rest of the Fluent Checklist
Sections 8 through 12 read more like conventional Fluent UI best practice, and move faster as a result. Composition (Section 8): use Fluent subcomponents like CardHeader rather than reassembling a component’s internal anatomy by hand, use proper Text hierarchy for size and weight, and avoid arbitrary spacing values. Interaction consistency (Section 9): keep hover, active, and focus states consistent, and don’t mix filled and regular icon variants within the same UI. Accessibility (Section 10) is the longest of this group and the least negotiable — semantic structure, full keyboard navigation, labels and accessible names, preserved tab order, managed focus for overlays, and explicit loading/empty/error states exposed to the user, not silently swallowed.
Performance (Section 11) stays intentionally light — favor lightweight composition, avoid excessive nesting, avoid heavy components unless justified — and styling (Section 12) circles back to the theme rules already established: prefer Fluent defaults, never assume fixed widths, keep things readable in narrow views, and use theme tokens rather than one-off values.
Anti-Patterns: The Six Things an Agent Should Refuse to Do
Section 13 collects the contract’s negative space into one tight list, and it’s worth reading as a single unit because it’s essentially the “don’t” version of everything above it:
Agents MUST NOT:
- recreate Fluent components manually
- assume full-screen layouts in embedded contexts
- use custom color systems
- overuse elevation
- create dense multi-column layouts in narrow spaces
- rely on hover-only affordances
If you’ve ever reviewed an AI-generated web part and felt something was off without being able to name it, it was probably one of these six.
What this means for you: paste this list into your agent’s system context verbatim and you’ve covered the most common review comments a Fluent UI PR gets, before the PR exists.
Data Access and Validation — and a Link That Doesn’t Resolve
The last three sections close the loop between design and delivery. Section 14 sets the output bar: React plus TypeScript, Fluent UI v9-based, readable and implementation-ready — no surprises there given everything above it.
Section 15 is where react-design.md hands off to the fourth reference file in the pack:
MUST use PnPjs by default for any SharePoint or Microsoft Graph data.
Data calls must live in a service or hook, never inline inside a render function, and every async data path must expose loading, empty, and error states — the same accessibility requirement from Section 10, applied specifically to data. This is the rule Post 8 will cover in full: “Why PnPjs Should Be Non-Negotiable in Every AI-Generated SPFx Web Part,” the pillar post for pnpjs.md itself.
Section 16, Validation, closes the file with a step that should feel familiar from Post 2’s toolchain table: run npm run build and resolve every error, then smoke-test in the workbench — heft start on SPFx v1.22+, gulp serve on the legacy toolchain.
Here’s the small, honest gap worth flagging: Section 16 links to ./toolchain.md for that Heft/gulp split, and as of this writing that file doesn’t exist in the repo’s references/ directory — which currently holds exactly four files: create.md, pnpjs.md, react-design.md, and upgrade.md. The actual toolchain decision rule lives inline in SKILL.md, under its own “Toolchain decision rule” heading. It’s a dangling link, not a missing feature — the guidance exists, filed one level up from where Section 16 points. If you’re implementing this contract for your own agent setup, look for the rule in SKILL.md rather than following that link.
What’s Next
Two posts from here follow the pattern this series has already used twice. Post 7 will be the roadmap companion to this one — untested, explicitly-labeled proposals for extending react-design.md, in the same “pre-PR working notes” spirit as Post 3’s scaffolding roadmap and Post 5’s upgrade-playbook roadmap. After that, Post 8 picks up the thread Section 15 opened: “Why PnPjs Should Be Non-Negotiable in Every AI-Generated SPFx Web Part,” the pillar post for the fourth and final reference file, pnpjs.md.