docs: add missing v8 to v9 migration guides - #36598
docs: add missing v8 to v9 migration guides#36598Paolo Aliprandi (paolo-aliprandi) wants to merge 23 commits into
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9faba520-fc05-4d3f-8ac5-e0146fdd09db
📊 Bundle size report✅ No changes found |
|
Pull request demo site: URL |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9faba520-fc05-4d3f-8ac5-e0146fdd09db
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9faba520-fc05-4d3f-8ac5-e0146fdd09db
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9faba520-fc05-4d3f-8ac5-e0146fdd09db
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9faba520-fc05-4d3f-8ac5-e0146fdd09db
Correct source-backed API details across the existing v8 migration guides and expand validation to cover every guide. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Reviewed the existing v8 → v9 migration documentation for consistency with the new guides:
|
Fold source-verified Drawer/Popover targeting, dismissal, focus, positioning, and unsupported-behavior guidance into the concise guides. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 39bc09e0-178f-4cdd-ad81-dbae05242afc
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 39bc09e0-178f-4cdd-ad81-dbae05242afc
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 39bc09e0-178f-4cdd-ad81-dbae05242afc
Added source-verified component behavior and accessibility edge cases to strengthen the v8 migration guidance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 39bc09e0-178f-4cdd-ad81-dbae05242afc
Documentation-only v8 → v9 migration verificationI completed the sealed migration verification pass for the expanded component Result
Final scenario matrix
The remaining
These are agent application misses, not missing or incorrect migration Corrective iteration ledger
Source-verified guide corrections
The structural documentation suite remains green: 139/139 tests, with |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 39bc09e0-178f-4cdd-ad81-dbae05242afc
Documentation-only migration verification: 53/53 focused guidesIsolation contract. Each focused verification used only the original v8 source and one guide. Network, MCP, external paths, dependency source/types, subagents, and ambient skills were blocked; build and lint were allowed. Summary. 53/53 launcher/build/lint/isolation checks passed. The latest hidden checklist was 50/53 PASS or VALID_VARIANT, with exactly three Corrected guide findings and clean reruns. Dialog now documents external-trigger focus restoration; Image now documents There were 139/139 structural tests, a clean git diff check, the prior 14/14 integration matrix, and 67 total scenarios. Commit:
|
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 39bc09e0-178f-4cdd-ad81-dbae05242afc
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 39bc09e0-178f-4cdd-ad81-dbae05242afc
Sync the final source-verified migration guidance from the 53-component benchmark, including responsive overflow, focus, navigation, selection, and theming corrections. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 39bc09e0-178f-4cdd-ad81-dbae05242afc
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 40efc87f-f280-4aea-8291-c7f54a734f30
| | ariaLabel | aria-label | | ||
| | itemCount | (removed) | | ||
| | itemIcon | icon (slot) | | ||
| | onRenderItemLink | (removed) | |
There was a problem hiding this comment.
onRenderItemLink has no same-named callback in v9, but its customization is preserved through Tab children rather than removed.
The v8 callback replaces the content rendered inside the tab header. In v9, render that custom JSX directly as the Tab content:
<Tab value="notifications">
<CustomTabContent icon={icon} label="Notifications" count={count} />
</Tab>Please map this to custom Tab children/content composition. Marking it as removed could lead developers to discard existing icons, counts, or other custom header content.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 40efc87f-f280-4aea-8291-c7f54a734f30
| | `placeholder` | `placeholder` | | | ||
| | `onChange` | `onChange` | Type changed: `(_, data: InputOnChangeData) => void`; dismiss fires with `data.value === ''` | | ||
| | `onSearch` | — | Use native `onKeyDown` checking `event.key === 'Enter'` | | ||
| | `onClear` | `onChange` with `''` | Dismiss button calls `onChange` with empty string | |
There was a problem hiding this comment.
Mapping onClear to any v9 onChange with an empty value does not preserve its semantics.
v8 calls onClear only when the user activates the clear button or clears with Escape. v9 onChange also reports data.value === '' when the user manually deletes the final character, so using the value alone would incorrectly invoke onClear in that case.
The clear-button path can be preserved through the dismiss slot, while the Escape path should call it from the custom Escape handler:
<SearchBox
dismiss={{ onClick: onClear }}
onChange={(_, data) => setQuery(data.value)}
onKeyDown={event => {
if (event.key === 'Escape' && query !== '') {
onClear(event);
// Preserve the remaining v8 Escape behavior.
}
}}
/>Please update the mapping to distinguish explicit clearing from an ordinary input change.
|
Implemented the second review round and validated it through executable v8→v9 migration benchmarks. Final docs head:
Median overall: 9.91; mean: 9.84. All 10 generated projects built and linted cleanly, and every generated Fluent API usage validated. The Tabs and RadioGroup browser-a11y deductions were generated-sample issues; both still received 10/10 migration fidelity. The TagPicker experiment exposed one remaining ambiguous sentence that still encouraged a global validation sequence. I clarified that independent candidates must not use latest-request-wins sequencing, reran the benchmark, and the generated implementation switched to per-candidate pending state plus functional reconciliation; its score improved from 9.63 to 9.89. Conclusion: the review comments are beneficial and the corrected docs should be accepted. Please re-review the final head. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 40efc87f-f280-4aea-8291-c7f54a734f30
|
Follow-up: the final docs head is now |
| /> | ||
| ); | ||
| }; | ||
| ``` |
There was a problem hiding this comment.
This example implements the opposite of shouldStartVisible.
In v8, shouldStartVisible={true} makes the image visible immediately and hides it only if loading fails. Initializing isLoaded to false and using hidden={!isLoaded} instead keeps the image hidden until it loads, which matches the default shouldStartVisible={false} behavior.
To preserve shouldStartVisible={true}, initialize the visibility state to true:
const [isVisible, setVisible] = useState(true);
<Image
src="..."
alt="Example image"
hidden={!isVisible}
onLoad={() => setVisible(true)}
onError={() => setVisible(false)}
/>| return ( | ||
| <> | ||
| <Label htmlFor={basicId}>Basic V9 example</Label> | ||
| <Slider id={basicId} /> |
There was a problem hiding this comment.
This is not equivalent to the basic v8 example because the default max changed.
v8 Slider defaults to a maximum of 10, while v9 defaults to 100. Although the difference is mentioned later in the guide, this migrated example currently changes the control’s range by a factor of ten.
Please preserve the v8 default here:
| <Slider id={basicId} max={10} /> |
| @@ -192,12 +201,12 @@ This table maps v8 `IChoiceGroupOption` props to the v9 `Radio` equivalent. | |||
| | `imageSize` | n/a | Use slots to customize `Radio` | | |||
| | `disabled` | `disabled` | | | |||
There was a problem hiding this comment.
This row documents disabled for an individual IChoiceGroupOption, but the guide does not document the separate group-level mapping.
v8 ChoiceGroup disabled disables every option, and v9 RadioGroup supports the same behavior directly:
<RadioGroup disabled={disabled}>
...
</RadioGroup>Please also add disabled to the preceding ChoiceGroup → RadioGroup table. Otherwise, developers may interpret this row as requiring disabled to be copied manually onto every Radio.
| | `Medium` | `"end"` | `"medium"` | | | ||
| | `Large` | `"end"` | `"large"` | | | ||
| | `LargeFixed` | `"end"` | `"large"` | | | ||
| | `ExtraLarge` | `"end"` | `"full"` | | |
There was a problem hiding this comment.
PanelType.extraLarge does not map directly to size="full".
At the largest breakpoint, the v8 extra-large Panel retains a 176px leading margin and fills only the remaining width. A v9 Drawer with size="full" is 100vw, so this mapping removes that margin and changes the Panel into a full-viewport surface.
This needs responsive custom sizing rather than the "full" preset—for example, preserving the source breakpoint behavior with makeStyles and a calculated width. Please document this as a custom CSS migration instead of a direct size mapping.
| } from '@fluentui/react-components'; | ||
| import { DismissRegular } from '@fluentui/react-icons'; | ||
|
|
||
| <OverlayDrawer open={isOpen} onOpenChange={(_, data) => setIsOpen(data.open)} position="end" size="medium"> |
There was a problem hiding this comment.
This example replaces the v8 onDismiss callback with a state update rather than preserving it.
The source uses onDismiss={handleClose}, so Escape and backdrop dismissal should still invoke handleClose. In the migrated example, those paths only call setIsOpen, meaning any cleanup, telemetry, or other effects inside the original callback are lost.
Map the callback explicitly:
| <OverlayDrawer open={isOpen} onOpenChange={(_, data) => setIsOpen(data.open)} position="end" size="medium"> | |
| <OverlayDrawer | |
| open={isOpen} | |
| onOpenChange={(event, data) => { | |
| if (!data.open) { | |
| handleClose(event); | |
| } | |
| }} | |
| position="end" | |
| size="medium" | |
| > |
The close button and Drawer dismissal paths should use the same migrated close policy.
|
|
||
| <div> | ||
| <Label htmlFor={errorId}>With Error Message</Label> | ||
| <Input id={errorId} aria-describedby={errorMessageId} /> |
There was a problem hiding this comment.
This is not equivalent to the v8 errorMessage example. v8 sets aria-invalid on the input and renders the error with role="alert", while this replacement only associates ordinary text through aria-describedby.
Please use Field so those validation semantics are preserved:
<Field label="With Error Message" validationState="error" validationMessage="Error message">
<Input />
</Field>| | `autoAjustHeight` | n/a | See `Textarea` docs | | ||
| | `autoAdjustHeight` | n/a | See `Textarea` docs | | ||
| | `underlined` | `appearance` | | | ||
| | `borderless` | `appearance` | | |
There was a problem hiding this comment.
borderless cannot be mapped to appearance. None of the supported v9 Input appearances removes the border: "outline" remains bordered, while the filled appearances add a background.
Please map this to a custom className/makeStyles override instead, as the Textarea migration guide already does. The underlined row above can specifically map to appearance="underline".
Summary
Adds and validates comprehensive v8-to-v9 migration documentation for mapped Fluent UI components.
Guide coverage
Breadcrumb, Calendar, Callout, CommandBar, DatePicker, DetailsList, Dialog, Dropdown/Combobox, FocusZone/FocusTrapZone, Icon, Link, List, MessageBar, Nav, OverflowSet, Panel, Persona, ProgressIndicator, Rating, SearchBox, Shimmer, SwatchColorPicker, TagPicker/PeoplePicker, TeachingBubble/Coachmark, Text, TimePicker, Toggle, and Tooltip.
ComboBox is covered by the shared Dropdown/Combobox guide. Stack and Stack.Item are covered by the existing Flex guides, with
StackShimandStackItemShimdocumented as temporary migration bridges.Existing documentation alignment
Validation
git diff --checkReview focus
This remains a draft for component-owner review, especially for behavioral edge cases where v8 has no one-to-one v9 prop mapping and for compatibility-component guidance.
Current working directory: /Users/paoloaliprandi/Desktop/fluent-genui-benchmark