Skip to content

feat: CSS animation callbacks on native - #10071

Merged
MatiPl01 merged 12 commits into
mainfrom
@matipl01/css-animation-callbacks-js
Aug 13, 2026
Merged

MatiPl01 merged 12 commits into
mainfrom
@matipl01/css-animation-callbacks-js

Conversation

@MatiPl01

@MatiPl01 MatiPl01 commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Makes onAnimationStart, onAnimationEnd, onAnimationIteration and onAnimationCancel fire on iOS and Android. They already work on web, and the shared types promised them everywhere, but native dropped them.

Callbacks are passed inside style, alongside the other CSS config props. Only the subscription mask crosses the JSI boundary, never the user function, and it is pushed to C++ only when the set of present callbacks changes.

A cancel emitted while the view is unmounting is still dropped here; #10255 delivers it.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 60559f17-44f7-4bfd-87db-ca5cd0be74b0

📥 Commits

Reviewing files that changed from the base of the PR and between 0fbbac2 and 7d427d7.

📒 Files selected for processing (2)
  • packages/react-native-reanimated/src/css/native/managers/CSSCallbacksManager.ts
  • packages/react-native-reanimated/src/css/native/managers/__tests__/CSSCallbacksManager.test.ts

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added support for CSS animation callbacks, including animation start and cancellation events.
    • Callback registrations now synchronize with running animations and are automatically managed during mounting and unmounting.
    • Expanded CSS event exports and event-mask support for more efficient native event handling.
  • Bug Fixes

    • Improved callback delivery when callbacks are added, removed, or changed while animations are active.
    • Prevented unsupported transition events from triggering animation callbacks.
    • Ensured cancellation events are handled correctly during animation detachment and cleanup.

Walkthrough

Native CSS animation callbacks now use event masks. CSSCallbacksManager registers callbacks, filters native events, and dispatches animation callbacks. CSSManager synchronizes callbacks and passes masks to CSSAnimationsManager, which updates native animation state when masks change.

Changes

Native CSS animation callbacks

Layer / File(s) Summary
CSS event mask contract
packages/react-native-reanimated/src/css/native/events/*, packages/react-native-reanimated/src/css/native/types/animation.ts, packages/react-native-reanimated/src/css/native/events/__tests__/mask.test.ts
Exports CSS event types and masks. Maps animation callback properties to combined event masks.
Callback and animation manager wiring
packages/react-native-reanimated/src/css/native/managers/CSSCallbacksManager.ts, packages/react-native-reanimated/src/css/native/managers/CSSManager.ts, packages/react-native-reanimated/src/css/native/managers/CSSAnimationsManager.ts
Synchronizes callback registrations, dispatches supported animation events, propagates event masks, and resets masks during detachment.
Manager behavior validation
packages/react-native-reanimated/src/css/native/managers/__tests__/*
Tests event-mask updates, callback delivery, registration lifecycle, callback removal, detachment, and unmount cleanup.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Mergeability Score: ⚪ Minimal · up to 7d427

The PR adds native CSS animation callbacks without any actionable merge-blocking risk remaining; it is merge-ready after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant CSSManager
  participant CSSCallbacksManager
  participant cssCallbacksRegistry
  participant CSSAnimationsManager
  CSSManager->>CSSCallbacksManager: synchronize animation callbacks
  CSSCallbacksManager->>cssCallbacksRegistry: register callback subscriber
  CSSManager->>CSSAnimationsManager: apply animation event mask
  cssCallbacksRegistry->>CSSCallbacksManager: deliver native CSS animation event
  CSSCallbacksManager->>CSSManager: invoke mapped callback
Loading

Possibly related PRs

Suggested reviewers: tjzel

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: native CSS animation callbacks for iOS and Android.
Description check ✅ Passed The description directly explains the native CSS animation callback support and its implementation constraints.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch @matipl01/css-animation-callbacks-js

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@MatiPl01 MatiPl01 self-assigned this Jul 27, 2026
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from 32ec074 to 3f45c1f Compare July 27, 2026 13:28
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch 2 times, most recently from 0cb1ca9 to 787bbd4 Compare July 27, 2026 14:31
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from 787bbd4 to 179d304 Compare July 27, 2026 14:43
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from 179d304 to 251a897 Compare July 27, 2026 14:46
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from 251a897 to e441039 Compare July 28, 2026 07:07
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from e441039 to efd411a Compare July 28, 2026 09:05
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from efd411a to db9736f Compare July 30, 2026 09:22
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from db9736f to 5ff8b5e Compare July 30, 2026 09:33
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from 5ff8b5e to 0b73ead Compare July 30, 2026 18:56
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from 0b73ead to 1d5871c Compare July 30, 2026 19:03
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch 2 times, most recently from 3cff5e0 to eff7536 Compare July 30, 2026 21:04
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from 4f67146 to dd5be47 Compare July 31, 2026 18:41
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from a4af454 to f74856b Compare August 3, 2026 10:20
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from f74856b to ad289d9 Compare August 11, 2026 18:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/react-native-reanimated/src/createAnimatedComponent/AnimatedComponent.native.tsx (1)

146-180: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Render settled props when no settled style exists.

_syncStylePropsBackToReact can populate state.settledProps without populating state.settledStyle when all settled keys come from animatedProps or inline top-level props. The render condition checks only state.settledStyle, so those completed animated props are not rendered by React.

Gate on either settled state field, and add the style override only when settledStyle exists.

Proposed fix
-    if (FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS && this.state.settledStyle) {
+    if (
+      FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS &&
+      (this.state.settledStyle || this.state.settledProps)
+    ) {
+      const settledStyle = this.state.settledStyle;
       return super.render({
         nativeID,
         ...filteredProps,
         ...this.state.settledProps,
-        style: [...flattenArray(filteredProps.style), this.state.settledStyle],
+        ...(settledStyle
+          ? { style: [...flattenArray(filteredProps.style), settledStyle] }
+          : {}),
         ...jestProps,
       });
     }

Also applies to: 445-450

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/react-native-reanimated/src/createAnimatedComponent/AnimatedComponent.native.tsx`
around lines 146 - 180, Update the render condition that applies settled state
to check whether either settledProps or settledStyle exists, so completed
animated props render even without settled styles. Only add the style override
when settledStyle is present, preserving the existing behavior for absent
settled state.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@packages/react-native-reanimated/src/createAnimatedComponent/AnimatedComponent.native.tsx`:
- Around line 146-180: Update the render condition that applies settled state to
check whether either settledProps or settledStyle exists, so completed animated
props render even without settled styles. Only add the style override when
settledStyle is present, preserving the existing behavior for absent settled
state.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8d1c823a-6c3d-4689-abbb-b427991b1c21

📥 Commits

Reviewing files that changed from the base of the PR and between c21f678 and ad289d9.

📒 Files selected for processing (7)
  • packages/react-native-reanimated/src/createAnimatedComponent/AnimatedComponent.native.tsx
  • packages/react-native-reanimated/src/css/component/AnimatedComponent.native.tsx
  • packages/react-native-reanimated/src/css/native/events/index.ts
  • packages/react-native-reanimated/src/css/native/events/mask.ts
  • packages/react-native-reanimated/src/css/native/managers/CSSCallbacksManager.ts
  • packages/react-native-reanimated/src/css/native/managers/__tests__/CSSCallbacksManager.test.ts
  • packages/react-native-reanimated/src/css/native/managers/__tests__/CSSManager.test.ts

@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from ad289d9 to fb7421c Compare August 11, 2026 23:51
@MatiPl01
MatiPl01 force-pushed the @matipl01/css-animation-callbacks-js branch from fb7421c to f40c75c Compare August 12, 2026 07:50
The mask helper is a lookup table, so asserting each entry restated it, and the
tag routing and unregistration were each covered at two layers. Keep the
behavioural assertion of each and drop the duplicate.

@tjzel tjzel left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just one nit

Comment thread packages/react-native-reanimated/src/common/constants/view.ts Outdated
Naming the sentinel meant touching the existing comparisons in
createAnimatedComponent, which this PR otherwise leaves alone.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants