Component
Utilities
(concretely: AvatarGroup, Button, Link, Avatar — plus TagGroup, InteractionTag and Accordion, which
are the same gap and are still open.)
Package version
@fluentui/react-headless-components-preview 0.2.5
React version
18.3.1
Environment
node v22.12.0
@fluentui/react-headless-components-preview 0.2.5
Current Behavior
Several headless subpaths publish a context's values hook and its types, but not the reader
— so a consumer composing their own parts cannot read what the subpath's own render functions
already provide.
The gap as measured before the fix:
| Subpath |
Published |
Missing |
./avatar-group |
AvatarGroupContextValue, both useAvatarGroupContextValues hooks |
the reader useAvatarGroupContext_unstable and the provider |
./button |
— |
the Button context |
./link |
— |
the Link context |
./avatar |
— |
the Avatar context |
./tag-group |
useTagGroupContextValues |
useTagGroupContext_unstable — still open |
| InteractionTag |
values hook (13 hits in-tree) |
the reader (zero hits) — still open |
./accordion |
useAccordionContext |
useAccordionItemContext, useAccordionHeaderContext — still open |
The package is internally inconsistent about this: Toolbar/useToolbar.ts:27 already does the right
thing —
export { useToolbarContext_unstable as useToolbarContext } from '@fluentui/react-toolbar'; — and
./avatar now does too. The others stop at the values hook.
This is not a nicety, and one instance was a measured rendering defect. For Button/Link/Avatar
the provider side was already correct: the headless renderers are verbatim re-exports of
Griffel's and already wrap subtrees in Griffel's ButtonContextProvider / LinkContextProvider /
AvatarContextProvider (renderMessageBarActions.tsx:23, renderMessageBarBody.tsx:19,
renderTag.tsx:18). The gap was entirely consumer-side — and because those providers are Griffel's
own context instances, a locally-declared context can never receive the values. A re-export is
the only fix available to a consumer.
Measured symptom: a styled Button inside a styled MessageBarActions rendered medium where
the @fluentui/react-components equivalent renders small, because the size the provider was
already publishing was unreachable. Context identity was verified directly
(ButtonContextProvider from the headless package === the one from @fluentui/react-button, and
likewise for Link and Avatar).
Expected Behavior
Every headless subpath that publishes a context's values hook also publishes its reader (and, where
the package owns the provider, the provider), so that a consumer building their own parts can
participate in the same contract the package's own render functions do.
Reproduction
// Today: there is nothing to import.
import { useAvatarGroupContext } from '@fluentui/react-headless-components-preview/avatar-group';
// ^ not exported
// And a locally-declared context is not a workaround for Button/Link/Avatar:
// the provider in the tree is Griffel's own instance, so a local context never receives values.
Steps to reproduce
- Compose a custom Button inside a headless
MessageBarActions.
- Try to read the
size the provider is publishing.
- Observe there is no exported reader, and that a locally-declared context reads its default.
Discovery context
Found during pixel-level verification of a styling layer built over
@fluentui/react-headless-components-preview — the layer supplies its own presentation for each
part, so it needs to read the look context the container publishes. The AvatarGroup and
Button/Link/Avatar instances were the ones that blocked shipped components; the TagGroup,
InteractionTag and Accordion instances were found by auditing the rest of the package for the same
shape and are listed above so the gap can be closed once rather than four times.
Proposed fix
One line per context in the component barrel, plus the matching subpath entry — the shape
Toolbar/useToolbar.ts:27 and Avatar/avatarContext.ts already use. For AvatarGroup that is a
small dedicated avatarGroupContext.ts module (mirroring ./avatar's) plus two barrel entries; for
Button/Link/Avatar, three dedicated context modules plus three barrel entries and three subpath
entries. Additive in every case — nothing that exists today changes meaning, and the API reports
regenerate cleanly.
A working implementation for four of the seven sites (AvatarGroup, Button, Link, Avatar) is
included in PR #[WINDMOD-PR-NUMBER] (commits 5a89364f3f and 9612d547d9), with the etc/*.api.md
files regenerated. The remaining three — TagGroup, InteractionTag, Accordion — want the same
one-line-per-context treatment and are not in that PR; a drafted TagGroup change type-checks
(exit 0) with a negative control that fails as expected (exit 2), and can be contributed here.
Happy to split the whole thing into a standalone PR against this issue.
Suggested severity
High - No workaround (for Button/Link/Avatar specifically: the provider is a foreign context
instance, so no consumer-side declaration can substitute).
Are you willing to submit a PR to fix?
yes
Component
Utilities
(concretely: AvatarGroup, Button, Link, Avatar — plus TagGroup, InteractionTag and Accordion, which
are the same gap and are still open.)
Package version
@fluentui/react-headless-components-preview0.2.5React version
18.3.1
Environment
Current Behavior
Several headless subpaths publish a context's values hook and its types, but not the reader
— so a consumer composing their own parts cannot read what the subpath's own render functions
already provide.
The gap as measured before the fix:
./avatar-groupAvatarGroupContextValue, bothuseAvatarGroupContextValueshooksuseAvatarGroupContext_unstableand the provider./button./link./avatar./tag-groupuseTagGroupContextValuesuseTagGroupContext_unstable— still open./accordionuseAccordionContextuseAccordionItemContext,useAccordionHeaderContext— still openThe package is internally inconsistent about this:
Toolbar/useToolbar.ts:27already does the rightthing —
export { useToolbarContext_unstable as useToolbarContext } from '@fluentui/react-toolbar';— and./avatarnow does too. The others stop at the values hook.This is not a nicety, and one instance was a measured rendering defect. For Button/Link/Avatar
the provider side was already correct: the headless renderers are verbatim re-exports of
Griffel's and already wrap subtrees in Griffel's
ButtonContextProvider/LinkContextProvider/AvatarContextProvider(renderMessageBarActions.tsx:23,renderMessageBarBody.tsx:19,renderTag.tsx:18). The gap was entirely consumer-side — and because those providers are Griffel'sown context instances, a locally-declared context can never receive the values. A re-export is
the only fix available to a consumer.
Measured symptom: a styled
Buttoninside a styledMessageBarActionsrendered medium wherethe
@fluentui/react-componentsequivalent renders small, because the size the provider wasalready publishing was unreachable. Context identity was verified directly
(
ButtonContextProviderfrom the headless package===the one from@fluentui/react-button, andlikewise for Link and Avatar).
Expected Behavior
Every headless subpath that publishes a context's values hook also publishes its reader (and, where
the package owns the provider, the provider), so that a consumer building their own parts can
participate in the same contract the package's own render functions do.
Reproduction
Steps to reproduce
MessageBarActions.sizethe provider is publishing.Discovery context
Found during pixel-level verification of a styling layer built over
@fluentui/react-headless-components-preview— the layer supplies its own presentation for eachpart, so it needs to read the look context the container publishes. The AvatarGroup and
Button/Link/Avatar instances were the ones that blocked shipped components; the TagGroup,
InteractionTag and Accordion instances were found by auditing the rest of the package for the same
shape and are listed above so the gap can be closed once rather than four times.
Proposed fix
One line per context in the component barrel, plus the matching subpath entry — the shape
Toolbar/useToolbar.ts:27andAvatar/avatarContext.tsalready use. For AvatarGroup that is asmall dedicated
avatarGroupContext.tsmodule (mirroring./avatar's) plus two barrel entries; forButton/Link/Avatar, three dedicated context modules plus three barrel entries and three subpath
entries. Additive in every case — nothing that exists today changes meaning, and the API reports
regenerate cleanly.
A working implementation for four of the seven sites (AvatarGroup, Button, Link, Avatar) is
included in PR #[WINDMOD-PR-NUMBER] (commits
5a89364f3fand9612d547d9), with theetc/*.api.mdfiles regenerated. The remaining three — TagGroup, InteractionTag, Accordion — want the same
one-line-per-context treatment and are not in that PR; a drafted TagGroup change type-checks
(exit 0) with a negative control that fails as expected (exit 2), and can be contributed here.
Happy to split the whole thing into a standalone PR against this issue.
Suggested severity
High - No workaround (for Button/Link/Avatar specifically: the provider is a foreign context
instance, so no consumer-side declaration can substitute).
Are you willing to submit a PR to fix?
yes