Skip to content

Components workstream #4274

Description

@JasonVMo

Summary

Prepare packages/agentic/components for trustworthy beta adoption and eventual
production use by coordinating component coverage, readiness signals, repeatable spec
generation, Fabric FocusZone completion, and the missing-component backlog. The
library already demonstrates the intended architecture, but it remains partial and
cannot make reliable compatibility claims until those foundations and platform gates
are in place.

Evidence labels used throughout this workstream: Observed = verified in this
repository, in a remote branch, or in an external repository read directly;
Inferred = a conclusion drawn from observed evidence; Confirmed = a statement
supplied by the owner in the task assignment.

Purpose and outcome

This workstream is about packages/agentic/components: the agent-generated Fluent
component library that is intended to replace the legacy packages/components,
packages/experimental, and packages/native catalogs for Windows and macOS.

Today that library is a credible but partial slice of the canonical Fluent Flex
design system, with no published notion of which parts are trustworthy, no repeatable
path from a design spec to a generated component, and no keyboard-focus container on
the platforms it targets.

The outcome is:

  1. a stated, testable readiness model so consumers can tell which components are
    safe to adopt and which are previews;
  2. a uniform, enforced coverage contract for every component, plus written
    instructions so a new component arrives with the same coverage as button;
  3. a reproducible spec ingestion and generation path from the canonical
    x3-design/fluent-design catalog into this repository, including drift detection;
  4. a Fabric FocusZone for macOS and React Native Windows that unblocks the
    focus-orchestrated components, while the Win32 Paper path keeps working; and
  5. a dependency-ordered plan for the 32 catalog components that are not generated
    yet
    , one issue per component, with blockers reassessed against current evidence.

Observed current baseline

The generated library

Observed. packages/agentic/components is
published as @fluentui-react-native/components at version 0.2.3
(package.json,
CHANGELOG.md). Its runtime
dependencies are only @fluentui-react-native/design,
@fluentui-react-native/framework-base, and @fluentui-react-native/callout (the
last is declared but unused in src, and is listed under furn.knip.ignoreDependencies).

Observed. It contains 18 higher-order components under
src/components: accordion,
avatar, badge, button, card, checkbox, divider, input, list-item,
listbox-item, menu-item, progress-bar, radio, skeleton, spinner, switch,
tab, tag.

Observed. It contains 5 primitives under
src/primitives:
checkbox-indicator, compound-item-layout, focus-visual, icon,
layout-stable-text. None of these corresponds to an entry in the canonical design
catalog; they are FURN implementation building blocks.

Observed. Every component and primitive is exported explicitly from
src/index.ts (175 lines, no
wildcard exports), including the use<Component>_unstable,
use<Component>Styles_unstable, and render<Component>_unstable pipeline stages.
src/index.test.ts asserts
that those exports exist.

Coverage

Observed. Coverage is colocated and nearly uniform, with measurable gaps:

Artifact Present Gap
<component>.test.tsx 18 / 18 components, 5 / 5 primitives Case counts range from 3 (divider) to 15 (button)
<component>.types.test.ts(x) 17 / 18 components, 5 / 5 primitives button has none - the canonical component is the only one without compile-time coverage
<component>.stories.tsx 18 / 18 components, 5 / 5 primitives -
SPEC.md + spec/ companions 18 / 18 components 0 / 5 primitives
__snapshots__ button, list-item, skeleton only 15 components have no resolved-output snapshot

Observed. Jest runs against the macOS platform preset
(furn.jestPlatform: "macos" in
package.json); the package has no
Windows or Win32 unit-test pass.

Observed. On-device validation is apps/storybook, which
loads packages/agentic/components/src/**/*.stories.?(ts|tsx) and
packages/native/Callout/src/**/*.stories.?(ts|tsx)
(apps/storybook/src/main.ts). Its automated
harness,
apps/storybook/windows-tests/storybook-smoke.test.cjs,
is broader than the render smoke list alone: it selects 14 story IDs in three
groups.

Group Stories Assertion
Render smoke, data-driven from scripts/smoke-stories.json 3 - components-button--default, primitives-icon--default, primitives-callout--default testID is displayed, plus one status string for Callout; writes a JSON artifact
Keyboard focus movement 1 - components-button--overview Click, then Tab, then HasKeyboardFocus on the next control
Focus regression, table-driven plus one bespoke case 10 - components-tag--default, components-accordion--default, components-tab--selected, components-listboxitem--default, components-checkbox--default, components-menuitem--selected, components-listitem--selected-focus, components-radio--default, components-switch--default, components-card--interactive Click, then HasKeyboardFocus is True and the app has not terminated

Observed. That is 11 focus assertions in total (Button Overview, the 9
table-driven cases, and the interactive Card) and on-device touchpoints for 11 of the
18 components - accordion, button, card, checkbox, list-item,
listbox-item, menu-item, radio, switch, tab, tag - plus the icon
primitive and Callout. Observed: avatar, badge, divider, input,
progress-bar, skeleton, and spinner have no on-device coverage, nor do the
checkbox-indicator, compound-item-layout, focus-visual, and
layout-stable-text primitives.

Observed. The harness is Windows-only: it runs under
testEnvironment: '@react-native-windows/automation' via
jest.windows.config.cjs, there is no
macOS equivalent, and no workflow under .github/workflows
references apps/storybook at all
, so nothing in the table above runs in CI.

Inferred. The gap is therefore not "almost no on-device coverage". It is that
meaningful Windows focus coverage exists but is unenforced, single-platform, and
concentrated on the focus axis, so it neither proves the cross-platform claim nor
covers seven components and four primitives at all.

Specs and their source

Observed. The canonical catalog is
x3-design/fluent-design, default branch main, HEAD
d334acf
at retrieval time. Its machine-readable index is
component-map.yaml,
which lists 50 components, each pointing at
plugins/components/skills/<name>/SKILL.md. The catalog has no primitives tier; it
classifies components as atom or molecule.

Observed. Nothing in this repository references x3-design, fluent-design, or
component-map.yaml. There is no ingestion script, no pinned source revision, and no
drift check. Spec provenance exists only implicitly, through flex-components:<name>
and flex-system:<name> identifiers written into the spec prose.

Observed. The two spec shapes differ. Upstream, a component owns SKILL.md,
usage.md, and platform folders (web/tokens.yaml, web/accessibility.md,
web/interaction.md, and optional mobile/**). Locally, a generated component owns a
flat SPEC.md plus a spec/ folder with tokens.yaml, accessibility.md,
interaction.md, usage.md, and staged specs under
specs/<name> are flat with SPEC.md
alongside its companions and an extra blockers.md.

Observed. The local button contract has drifted from the upstream one. Upstream
button removed the Selected axis, renamed Radius to Shape, and split the icon slot
into independent leading and trailing slots (upstream plugin changelog, v1.4.0, and
the current components-index skill map). The local
button.types.ts
still exposes selected, a single icon slot with iconPosition, and
shape: 'rounded' | 'square' | 'circle' against the upstream Rounded/Circular pair.

Focus

Observed. packages/components/FocusZone
(@fluentui-react-native/focus-zone 0.23.2) is the only focus container in the
repository. It has a macOS Paper implementation (macos/RCTFocusZone.m and
macos/RCTFocusZoneManager.m), no windows/ directory, and a
codegenNativeComponent('RCTFocusZone') spec with no Fabric name mapping. It is built
on @uifabricshared/foundation-composable.

Observed. packages/agentic/components does not depend on, import, or render
FocusZone anywhere.

Observed. The blocker records for toolbar, tablist, radio-group, and menu
all cite the absence of a focus/roving-tabindex contract inside the agentic package as
a reason those components were not generated.

Beta versus production

The baseline above supports the following working distinction.

Beta means the library is honestly labeled and safely adoptable for the components
it claims:

  • every exported component carries a machine-readable readiness level and the spec
    revision it was generated from;
  • the coverage contract is uniform and enforced, so "it has tests" means the same
    thing for every component;
  • macOS and React Native Windows Fabric are both exercised on device for the
    beta-marked set, not only in a macOS-preset Jest run;
  • the catalog gap is enumerated, dependency-ordered, and public, so a consumer can see
    what is coming rather than discovering absence;
  • spec ingestion is reproducible from a pinned upstream revision, and drift against
    that revision is detectable.

Production means the library can replace the legacy catalogs:

  • every canonical catalog component is either implemented at production readiness or
    explicitly declined with a recorded rationale;
  • focus, keyboard, and screen-reader behavior is validated on each supported desktop
    endpoint rather than asserted in a unit test;
  • readiness levels are gated by automation in CI rather than by author assertion;
  • ingestion drift is a build failure, not a discovery;
  • the Win32 Paper endpoint continues to work for the components that ship there.

Staged roadmap

Stage 0: Approve scope

Stage 1: Establish beta foundations

Stage 2: Deliver beta

  • Generate wave 1 of the missing components (no new infrastructure required).
    ToggleButton starts only after the Button alignment decision lands.
  • Generate wave 2, the overlay and popover stack.
  • Mark the beta set and satisfy the beta exit criteria below.

Stage 3: Harden for production

  • Generate wave 3, the focus-orchestrated containers.
  • Resolve wave 4, the platform and native decisions.
  • Promote components to production readiness and satisfy the production exit
    criteria below.

Primary tasks

Task Stage Summary
Component tests 1 Close the measured coverage gaps (missing button type test, 15 components without snapshots, uneven case counts, no Windows unit pass), define a minimum coverage contract, enforce it, and publish authoring instructions for new components.
FocusZone 1 Finish the Fabric FocusZone started on origin/user/jasonvmo/fabric-focus-zone for macOS and React Native Windows, keep the Win32 Paper path unchanged, and decide how agentic components consume roving focus.
Readiness 1 Define readiness levels with objective, checkable evidence; decide where the marker lives and how it is published. A provisional initial assessment of all 23 exported items is already in that document; the task ratifies it, persists the markers, and automates promotion.
Spec patterns 1 Make the spec pipeline reproducible: pin the upstream revision, define the transform from the upstream SKILL.md + platform-folder shape to the local SPEC.md + spec/ shape, ingest new specs on demand, and report drift.
Missing components 2-3 32 dependency-ordered component tasks covering every canonical catalog entry that is not generated, with blockers reassessed against current evidence.
Primitives boundary 0-1 Decide the public contract for each FURN-only primitive, inventory consumers, define its spec policy, and align exports, coverage, and readiness evidence without changing primitive behavior.
Button and ToggleButton alignment 0-1 Decide whether Button retains or removes its Selected axis, resolve its related shape and icon-slot drift, and establish the stable contract that the ToggleButton task must consume.
Accessibility conformance suite 1 Add a typed applicability registry and shared Jest conformance runner for role, name, state, disabled semantics, decorative output, and required-prop warnings across every exported component.

Missing-component tasks

Wave 1 - local component dependencies already generated

Wave 2 - overlay and popover stack

Wave 3 - focus-orchestrated and composed

Wave 4 - platform or native decision required

Provisional readiness assessment

Inferred, and provisional pending owner approval. The full table, ladder, and
per-item evidence are in
readiness-model.md.

All 18 components and all 5 primitives are provisionally experimental today, and
the reason is infrastructural rather than per-component. Two axes fail universally: no
spec provenance is recorded anywhere in the repository, and the only on-device harness
is Windows-only and unenforced, so nothing can satisfy a two-platform validation
requirement.

Inferred. Once those two gates clear, existing evidence would separate the library
as follows:

Ceiling after the universal gates clear Count Items and the axis that still limits them
beta 1 list-item - the only component with a type test, a snapshot, and an on-device case together
preview 16 The remaining components. Nine are limited by contract coverage alone (no resolved-output record for a state-dependent visual contract): accordion, card, checkbox, listbox-item, menu-item, radio, switch, tab, tag. Four are limited by platform validation alone (no on-device case at all): avatar, badge, progress-bar, skeleton. Three are limited by both: divider, input, spinner
experimental 1 component + 5 primitives button, held back by the package's only missing type test and by a spec contract drifted from upstream. All five primitives, which have no SPEC.md and no upstream catalog entry, so the spec-fidelity axis cannot be evaluated at all

Inferred. The practical reading: the canonical component is the least ready one,
the gap for the sixteen preview items is small and mechanical, and the primitives'
ceiling is a scoping decision rather than a coverage gap.

Missing-component rollup

Observed. The canonical catalog has 50 components; 18 are generated. The gap is
32 components, enumerated one task per component in
tasks/missing-components/.

Wave Theme Count Components
1 Dependencies already generated 11 avatar-group, destructive-button, interaction-tag, label, link, list, message-bar, nav-item, search-box, textarea, toggle-button
2 Overlay and popover stack 9 combobox, dialog, drawer, dropdown, menu, popover, teaching-popover, toast, tooltip
3 Focus-orchestrated and composed 10 breadcrumb, field, info-label, menu-button, nav, radio-group, simple-nav, split-button, tablist, toolbar
4 Platform or native decision required 2 scrollbar, select

Observed. 18 of the 32 already have staged spec folders under
packages/agentic/components/specs with a
blockers.md record; the other 14 have no local presence at all and must be ingested
first.

Observed. Several recorded blockers are artifacts of the generation session's
scope rather than technical limits. list, tablist, radio-group, and menu were
all blocked on dependencies (list-item, tab, radio, menu-item, divider) that
are now generated, and interaction-tag was blocked because the session was forbidden
from editing src/index.ts. Each missing-component task restates the blocker and
records whether current evidence still supports it.

Cross-task dependencies

  1. primitives-boundary.md resolves whether
    primitives belong in the public readiness and coverage contracts.
  2. button-toggle-button-alignment.md
    blocks Toggle Button; the
    package must not publish two overlapping toggle contracts by accident.
  3. accessibility-conformance-suite.md
    depends on component-test-strategy.md
    and supplies machine-readable accessibility evidence to the readiness model.
  4. readiness-model.md depends on
    component-test-strategy.md for the evidence
    that a readiness level asserts. Levels defined without an enforced coverage
    contract are self-reported.
  5. spec-ingestion-and-generation.md blocks
    the 14 components that have no local spec, and supplies the drift report that
    readiness-model.md uses to decide whether a generated
    component still matches its source.
  6. focus-zone.md blocks the roving-focus components in wave 3
    (toolbar, tablist, radio-group, nav, simple-nav) and the focus-trap
    requirement in drawer and dialog.
  7. popover is the keystone of wave 2. combobox, dialog, dropdown, menu,
    teaching-popover, toast, and tooltip all depend on the overlay, anchoring, and
    light-dismiss behavior it establishes, and wave 3's breadcrumb, info-label,
    menu-button, and split-button depend on wave 2 through it.
  8. label blocks field and the radio-group legend; nav-item blocks nav and
    simple-nav; toggle-button blocks toolbar.
  9. The Components workstream depends on
    Infrastructure for on-device desktop test execution:
    platform validation claims in every task here are only automatable once the
    Storybook end-to-end pipeline exists.
  10. The Components workstream depends on Theming for the Flex
    token surface that generated components style against; recorded token gaps in
    component specs should be resolved there rather than worked around per component.

Beta exit criteria

  • The coverage contract is written down, and every exported component and
    primitive satisfies it, including a button type test and snapshots for the
    components whose visual contract is state-dependent.
  • yarn workspace @fluentui-react-native/components test passes on the macOS
    preset, and an equivalent Windows pass exists or its absence is a recorded,
    accepted risk.
  • Every exported component carries a readiness level and the upstream spec
    revision it was generated from, published in a place a consumer can read without
    cloning the repository.
  • The upstream catalog revision is pinned in-repo, and a drift report exists for
    all 18 generated components, with button's known divergence either resolved or
    recorded as an accepted deviation.
  • FocusZone works on macOS Fabric and React Native Windows Fabric, the Win32 Paper
    path is unchanged, and the agentic package has a decided, documented way to get
    roving focus.
  • Every exported primitive has an explicit public, package-private, or
    separate-package disposition and a matching contract policy.
  • Button's upstream drift is resolved or recorded as an approved deviation,
    and ToggleButton consumes that decision.
  • Every exported higher-order component has an accessibility conformance
    registry entry and passes the shared static-native-output suite.
  • Wave 1 and wave 2 missing components are either generated at beta readiness or
    have a recorded, evidence-backed blocker.
  • Storybook stories for every beta-marked component have documented runs on
    macOS and React Native Windows Fabric. A reviewed manual macOS run may
    satisfy beta; required CI enforcement is a production gate.

Production exit criteria

  • All 50 canonical catalog components are implemented at production readiness or
    explicitly declined, with the decision and rationale recorded next to the catalog
    inclusion rules.
  • Readiness levels are computed and gated by CI, and a component cannot be marked
    above its evidence.
  • Keyboard, focus, and screen-reader behavior is validated on each supported
    desktop endpoint for every production-marked component, not asserted only in
    Jest.
  • Spec drift against the pinned upstream revision fails the build.
  • The Win32 Paper endpoint still passes its FocusZone end-to-end suites.
  • Every component that replaced a legacy packages/components,
    packages/experimental, or packages/native component has a recorded migration
    note, and the legacy package is marked accordingly.

Cross-workstream infrastructure

The owner-approved bundle-size and dependency-budget addition is tracked by
Add bundle-size and dependency regression gates.
The Components workstream owns the allowed source and dependency boundary; the
Infrastructure workstream owns the repeatable consumer bundles, checked-in
budgets, and CI enforcement.

Suggested additions

These are decision-gated and intentionally have no task files. They came out of
the research but are not part of the current scope.

  1. Legacy catalog migration map. Produce a per-component mapping from
    packages/components, packages/experimental, and packages/native to the
    agentic equivalent, with a deprecation policy. The agentic library currently
    duplicates Avatar, Badge, Button, Checkbox, Divider, Input, Switch,
    and Tab without any statement about which one a consumer should use.
  2. Mobile spec coverage. The upstream catalog carries mobile/ios and
    mobile/android companions for a growing subset of components. The local specs
    ingest only the desktop-facing content. Decide whether FURN's agentic library is
    desktop-only by policy.

Sources

All sources retrieved 2026-08-20.

Source Reference
Generated library packages/agentic/components
Staged specs packages/agentic/components/specs
Authoring rules packages/agentic/components/AGENTS.md, src/AGENTS.md, src/components/AGENTS.md, src/primitives/AGENTS.md
Authoring skill .github/skills/agentic-component-authoring
Storybook app apps/storybook
FocusZone packages/components/FocusZone
Canonical catalog x3-design/fluent-design @ d334acf, component-map.yaml, components-index/SKILL.md
Fabric FocusZone branch origin/user/jasonvmo/fabric-focus-zone @ ea2a704

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions