Skip to content

feat(react-motion): add replayKey prop to replay motion without remounting#36108

Open
robertpenner wants to merge 10 commits into
microsoft:masterfrom
robertpenner:feat/motion-component-replay-key
Open

feat(react-motion): add replayKey prop to replay motion without remounting#36108
robertpenner wants to merge 10 commits into
microsoft:masterfrom
robertpenner:feat/motion-component-replay-key

Conversation

@robertpenner
Copy link
Copy Markdown
Collaborator

@robertpenner robertpenner commented May 6, 2026

  • Add an optional replayKey prop to MotionComponentProps.
  • When the value changes, the animation effect re-runs — cancelling any in-progress animation and replaying from the start on the same DOM element, without remounting the component or its children.
  • Includes tests verifying replay behaviour, DOM continuity, callbacks firing on replay (onMotionStart/onMotionFinish), and skip-motion fast-forward on replay.
  • Adds a Storybook story with a side-by-side before/after demo.
image

Previous Behavior

To retrigger a motion animation on an already-mounted component, the only declarative option was to change the React key prop, which forces a full unmount and remount of the subtree. This destroys the DOM nodes, resets child component state, and loses focus — even when all you want is to replay the animation.

New Behavior

MotionComponent accepts an optional replayKey prop (string | number). When the value changes, the animation replays from the beginning on the existing DOM element — cancelling any in-progress animation — without unmounting or remounting the component or its children. DOM continuity, focus, and child state are all preserved.

const [replayKey, setReplayKey] = React.useState(0);

<Fade.In replayKey={replayKey}>
  <div>Content</div>
</Fade.In>
<button onClick={() => setReplayKey(k => k + 1)}>Replay</button>

Future Work

@robertpenner robertpenner self-assigned this May 6, 2026
@robertpenner robertpenner force-pushed the feat/motion-component-replay-key branch from dd35075 to 0967549 Compare May 6, 2026 05:57
@robertpenner robertpenner force-pushed the feat/motion-component-replay-key branch from 0967549 to 864d814 Compare May 7, 2026 14:35
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-accordion
Accordion (including children components)
92.107 kB
29.097 kB
92.263 kB
29.152 kB
156 B
55 B
react-charts
AreaChart
402.548 kB
125.863 kB
402.705 kB
125.924 kB
157 B
61 B
react-charts
DeclarativeChart
753.304 kB
220.052 kB
753.461 kB
220.1 kB
157 B
48 B
react-charts
DonutChart
312.961 kB
96.495 kB
313.118 kB
96.551 kB
157 B
56 B
react-charts
FunnelChart
304.508 kB
93.326 kB
304.665 kB
93.387 kB
157 B
61 B
react-charts
GanttChart
385.649 kB
120.152 kB
385.805 kB
120.192 kB
156 B
40 B
react-charts
GaugeChart
312.394 kB
95.948 kB
312.551 kB
96.005 kB
157 B
57 B
react-charts
GroupedVerticalBarChart
393.525 kB
122.894 kB
393.682 kB
122.935 kB
157 B
41 B
react-charts
HeatMapChart
387.728 kB
121.263 kB
387.885 kB
121.32 kB
157 B
57 B
react-charts
HorizontalBarChart
292.691 kB
89.04 kB
292.848 kB
89.089 kB
157 B
49 B
react-charts
Legends
232.228 kB
69.849 kB
232.384 kB
69.894 kB
156 B
45 B
react-charts
LineChart
413.882 kB
128.765 kB
414.039 kB
128.807 kB
157 B
42 B
react-charts
PolarChart
341.357 kB
106.417 kB
341.514 kB
106.461 kB
157 B
44 B
react-charts
SankeyChart
209.97 kB
67.042 kB
210.127 kB
67.099 kB
157 B
57 B
react-charts
ScatterChart
393.264 kB
122.86 kB
393.421 kB
122.904 kB
157 B
44 B
react-charts
VerticalBarChart
430.006 kB
127.714 kB
430.163 kB
127.775 kB
157 B
61 B
react-charts
VerticalStackedBarChart
399.53 kB
124.283 kB
399.687 kB
124.326 kB
157 B
43 B
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
226.994 kB
68.166 kB
227.15 kB
68.229 kB
156 B
63 B
react-components
react-components: entire library
1.292 MB
324.681 kB
1.292 MB
324.736 kB
157 B
55 B
react-dialog
Dialog (including children components)
91.172 kB
28.31 kB
91.329 kB
28.371 kB
157 B
61 B
react-menu
Menu (including children components)
160.425 kB
50.891 kB
160.581 kB
50.94 kB
156 B
49 B
react-menu
Menu (including selectable components)
163.603 kB
51.535 kB
163.759 kB
51.585 kB
156 B
50 B
react-motion
@fluentui/react-motion - createMotionComponent()
4.156 kB
1.818 kB
4.312 kB
1.876 kB
156 B
58 B
react-motion
@fluentui/react-motion - createPresenceComponent()
5.908 kB
2.442 kB
6.064 kB
2.494 kB
156 B
52 B
react-popover
Popover
123.802 kB
39.735 kB
123.958 kB
39.789 kB
156 B
54 B
react-progress
ProgressBar
20.23 kB
7.866 kB
20.386 kB
7.925 kB
156 B
59 B
react-teaching-popover
TeachingPopover
102.196 kB
32.335 kB
102.352 kB
32.384 kB
156 B
49 B
react-toast
Toast (including Toaster)
92.099 kB
28.662 kB
92.256 kB
28.712 kB
157 B
50 B
react-tree
FlatTree
136.789 kB
40.787 kB
136.945 kB
40.84 kB
156 B
53 B
react-tree
PersonaFlatTree
138.617 kB
41.303 kB
138.773 kB
41.354 kB
156 B
51 B
react-tree
PersonaTree
134.677 kB
40.086 kB
134.833 kB
40.137 kB
156 B
51 B
react-tree
Tree
132.855 kB
39.62 kB
133.011 kB
39.673 kB
156 B
53 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
react-avatar
Avatar
48.492 kB
15.379 kB
react-avatar
AvatarGroup
17.468 kB
6.999 kB
react-avatar
AvatarGroupItem
61.513 kB
19.251 kB
react-breadcrumb
@fluentui/react-breadcrumb - package
103.889 kB
29.167 kB
react-charts
HorizontalBarChartWithAxis
63 B
83 B
react-charts
Sparkline
80.503 kB
26.644 kB
react-components
react-components: Button, FluentProvider & webLightTheme
67.61 kB
19.536 kB
react-components
react-components: FluentProvider & webLightTheme
40.806 kB
13.616 kB
react-datepicker-compat
DatePicker Compat
214.121 kB
62.046 kB
react-headless-components-preview
react-headless-components-preview: entire library
107.897 kB
31.819 kB
react-message-bar
MessageBar (all components)
23.418 kB
8.651 kB
react-motion
@fluentui/react-motion - PresenceGroup
1.727 kB
823 B
react-overflow
hooks only
11.966 kB
4.565 kB
react-persona
Persona
55.447 kB
17.311 kB
react-portal-compat
PortalCompatProvider
5.567 kB
2.237 kB
react-table
DataGrid
148.07 kB
44.013 kB
react-table
Table (Primitives only)
38.209 kB
12.782 kB
react-table
Table as DataGrid
119.815 kB
33.806 kB
react-table
Table (Selection only)
66.603 kB
19.023 kB
react-table
Table (Sort only)
65.246 kB
18.638 kB
react-tag-picker
@fluentui/react-tag-picker - package
174.546 kB
54.381 kB
react-tags
InteractionTag
13.742 kB
5.473 kB
react-tags
Tag
29.666 kB
9.433 kB
react-tags
TagGroup
71.009 kB
21.901 kB
react-timepicker-compat
TimePicker
105.613 kB
35.351 kB
🤖 This report was generated against db585d2ae06bbdb75de752d2aaa3347979f7b816

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

Pull request demo site: URL

@robertpenner robertpenner marked this pull request as ready for review May 7, 2026 15:32
@robertpenner robertpenner requested review from a team as code owners May 7, 2026 15:32
@robertpenner robertpenner requested a review from layershifter May 7, 2026 15:32
@robertpenner robertpenner force-pushed the feat/motion-component-replay-key branch from 68ec731 to bc88d21 Compare May 8, 2026 15:23
@robertpenner robertpenner moved this to Ready for review in 🏄🏻‍♂️ Fluent Motion May 8, 2026
@robertpenner robertpenner force-pushed the feat/motion-component-replay-key branch from bc88d21 to 35c8ed7 Compare May 11, 2026 13:12
…nting

Add an optional replayKey prop to MotionComponentProps. When the value
changes, the animation effect re-runs — cancelling any in-progress
animation and replaying from the start on the same DOM element, without
remounting the component or its children. Includes tests verifying both
replay behaviour and DOM continuity.
@robertpenner robertpenner force-pushed the feat/motion-component-replay-key branch from fce9549 to 9a7dac0 Compare May 12, 2026 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Ready for review

Development

Successfully merging this pull request may close these issues.

1 participant