Skip to content

Commit 1ec3a68

Browse files
Add React Native 0.88 release blog post (#5283)
1 parent 35d19a6 commit 1ec3a68

1 file changed

Lines changed: 254 additions & 0 deletions

File tree

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
---
2+
title: 'React Native 0.88 - Web-Based Event Dispatching, Variable Fonts, SceneDelegate, no breaking changes'
3+
authors: [fabriziocucci, cipolleschi, chrfalch]
4+
tags: [announcement, release]
5+
date: 2026-10-19
6+
---
7+
8+
# React Native 0.88 - Web-Based Event Dispatching, Variable Fonts, SceneDelegate, no breaking changes
9+
10+
Today we are excited to release React Native 0.88!
11+
12+
This release switches event dispatching to the Web-based path by default, brings variable fonts to `Text` and `TextInput` on both platforms and adds `SceneDelegate` lifecycle support on iOS. It also bumps the React version to 19.3.0 and moves to Metro 0.87.
13+
14+
Following [0.83](/blog/2025/12/10/react-native-0.83) and [0.86](/blog/2026/06/11/react-native-0.86), this is the third React Native release with no user-facing breaking changes, reflecting our continued commitment to making upgrades more predictable and seamless.
15+
16+
## Highlights
17+
18+
- [Web-based event dispatching](/blog/2026/10/19/react-native-0.88#web-based-event-dispatching)
19+
- [Variable fonts with fontVariationSettings](/blog/2026/10/19/react-native-0.88#variable-fonts-with-fontvariationsettings)
20+
- [SceneDelegate lifecycle support on iOS](/blog/2026/10/19/react-native-0.88#ios-scenedelegate-support)
21+
- [ArrayBuffer for Java TurboModules](/blog/2026/10/19/react-native-0.88#arraybuffer-for-java-turbomodules)
22+
- [Experimental Swift Package Manager support](/blog/2026/10/19/react-native-0.88#experimental-swift-package-manager-support)
23+
24+
{/* truncate */}
25+
26+
## Web-based event dispatching
27+
28+
React Native now dispatches events through the W3C [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) API by default, replacing the plugin-based system the renderer has used since its early days. Unblocked by the react@19.3.0 bump in this release, it is the largest runtime change in 0.88.
29+
30+
Events now travel a real capture path down to the target and bubble back up, over nodes that are genuine event targets. The payoff:
31+
32+
- **The same model as the web**: Propagation, `capture`, `stopPropagation()` and `preventDefault()` are no longer a React Native reimplementation of the DOM. Libraries that reason about event flow can increasingly be written once, against one model.
33+
- **A path to Web-compatible imperative APIs**: Canary builds expose `addEventListener`, `removeEventListener` and `dispatchEvent` on native refs for early feedback.
34+
- **One path to maintain**: Removing the legacy plugin registry is the follow-up, leaving a single dispatch path instead of two.
35+
36+
The imperative API is available on the [Canary channel](/docs/releases/release-levels) in 0.88:
37+
38+
```tsx
39+
const ref = useRef(null);
40+
41+
useEffect(() => {
42+
const onClick = event => {
43+
// ...
44+
};
45+
ref.current?.addEventListener('click', onClick);
46+
return () => ref.current?.removeEventListener('click', onClick);
47+
}, []);
48+
```
49+
50+
On Canary, if an element has both a declarative prop and an imperative listener for the same event, the prop runs first.
51+
52+
#### What this means for your app
53+
54+
Nothing should change. Your event props keep the same names, receive the same synthetic event objects (`nativeEvent`, `persist()` and the rest) and run in the same order. Direct events such as `onLayout` still fire only on the target. Errors still reach React error boundaries synchronously. The touch responder system is unchanged.
55+
56+
The code to test is anything reaching past the public API into React Native’s event internals, since the plugin registry it was written against is no longer the path events take. The legacy path is still present in 0.88 behind an internal flag, but it is expected to be removed with the follow-up, so please report anything that only works the old way.
57+
58+
## Variable fonts with fontVariationSettings
59+
60+
`fontVariationSettings` is now supported on both `<Text>` and `<TextInput>`, on Android and iOS. Both the CSS string form and an object form are accepted:
61+
62+
```tsx
63+
<Text style={{fontVariationSettings: {wght: 700, slnt: -10}}}>Object form</Text>
64+
<Text style={{fontVariationSettings: "'wght' 700, 'slnt' -10"}}>String form</Text>
65+
```
66+
67+
Object keys are four-character axis tags with finite numeric values.
68+
69+
## ArrayBuffer for Java TurboModules
70+
71+
Java TurboModules can now take and return JavaScript `ArrayBuffer` values directly. Codegen maps them to `com.facebook.react.bridge.ArrayBuffer`, so binary data no longer needs to be encoded as strings or number arrays:
72+
73+
```diff
74+
export interface Spec extends TurboModule {
75+
- process(data: string): string; // for example, Base64
76+
+ process(data: ArrayBuffer): ArrayBuffer;
77+
}
78+
```
79+
80+
For synchronous methods, inputs can borrow JavaScript memory and avoid a copy. Those borrowed bytes are valid only until the method returns. If you need to retain them, copy them during the call:
81+
82+
```kotlin
83+
override fun keepForLater(data: ArrayBuffer) {
84+
retained = ArrayBuffer.arrayBufferWithCopiedBytes(data)
85+
}
86+
```
87+
88+
Accessing `ArrayBuffer.bytes` or `ArrayBuffer.size` after a borrowed buffer has been revoked throws an `IllegalStateException`.
89+
90+
## iOS: SceneDelegate support
91+
92+
Starting with the iOS 27 SDK, Apple requires the [UIScene lifecycle](https://developer.apple.com/documentation/uikit/transitioning-to-the-uikit-scene-based-life-cycle): UIKit apps built with Xcode 27 will fail to launch.
93+
94+
React Native 0.88 introduces support for this lifecycle as an additive change, keeping backwards compatibility with the `AppDelegate` path. `RCTReactNativeFactory` gains two new SceneDelegate entry points:
95+
96+
- `startReactNativeWithModuleName:inWindow:connectionOptions:`
97+
- `startReactNativeWithModuleName:inWindow:initialProperties:connectionOptions:`
98+
99+
Support in 0.88 is limited to a single scene, so keep `UIApplicationSupportsMultipleScenes` set to `false`. At launch, React Native forwards only the first URL context or user activity from the scene’s connection options.
100+
101+
To migrate, you need to:
102+
103+
- move the React Native entry point from your `AppDelegate` to a `SceneDelegate`
104+
- forward the scene’s URL and user-activity callbacks to `RCTLinkingManager`
105+
- add a `UIApplicationSceneManifest` key to `Info.plist`.
106+
107+
The community template [has been updated](https://react-native-community.github.io/upgrade-helper/), so newly created apps already use the new entry point. You can use the community template or the upgrade helper, as an example to migrate your app, specifically the [`SceneDelegate.swift`](https://github.com/react-native-community/template/blob/0.88-stable/template/ios/HelloWorld/SceneDelegate.swift) and [`Info.plist`](https://github.com/react-native-community/template/blob/0.88-stable/template/ios/HelloWorld/Info.plist) files.
108+
109+
With the UIScene lifecycle, the app window is resizable. `Dimensions.get()` and `useWindowDimensions()` update with the current values.
110+
111+
## Experimental: Swift Package Manager support
112+
113+
Swift Package Manager support remains experimental and opt-in in React Native 0.88, while CocoaPods remains fully supported. Since the preview in 0.87, we have hardened the tooling using feedback from real apps and libraries.
114+
115+
Our current rollout plan is:
116+
117+
- **0.87**: Introduced experimental Swift Package Manager support.
118+
- **0.88**: Hardened the scripts to support more libraries and edge cases.
119+
- **0.89**: Target Swift Package Manager as the default, with an opt-out to CocoaPods for apps that are still blocked.
120+
121+
We plan to remove CocoaPods support in a later release of React Native.
122+
123+
Please try the preview and report blockers in [RFC #0994](https://github.com/react-native-community/discussions-and-proposals/pull/994).
124+
125+
Please refer to the [blogpost for React Native 0.87](/blog/2026/08/11/react-native-0.87#experimental-swift-package-manager-support-for-ios) for instructions on how to opt-in.
126+
127+
### Swift Package Manager Improvements
128+
129+
The `npx react-native spm` tooling shipped in 0.87, has been improved in 0.88 with fixes from real apps and libraries, so SwiftPM projects build more reliably in Xcode and on the command line.
130+
131+
<details>
132+
<summary>**List of improvements**</summary>
133+
134+
- **iOS version is read from the app**: Generated manifests now take their minimum iOS version from the app's deployment target, not a hardcoded iOS 15. Packages that need a newer iOS version, such as Expo's, can now be autolinked
135+
- **Stable Xcode builds**: Xcode builds no longer break for libraries that ship their own `Package.swift`
136+
- **Portable projects**: Apps no longer commit a machine-specific Hermes compiler path
137+
- **Bash for build scripts**: Generated build scripts now run under bash
138+
- **Configuration in package.json**: Libraries can now declare their SwiftPM settings in `package.json`’s `swiftpmConfig` section. The Swift Package Manager block in `react-native.config.js` is deprecated
139+
- **Names from the podspec**: When a library declares no SwiftPM name, the scaffolder takes it from the podspec.
140+
- **Mirror-first artifact downloads**: Prebuilt artifacts now download from the React Native Maven mirror first, with Maven Central as fallback.
141+
142+
</details>
143+
144+
## Breaking Changes
145+
146+
React Native 0.88 has **no user-facing breaking changes**.
147+
148+
If you are on React Native 0.87, you should be able to upgrade your app to React Native 0.88 without any changes to your app code.
149+
150+
To learn more about what we consider a breaking change, have a look at [this article](/releases/versioning-policy#what-is-a-breaking-change).
151+
152+
## Deprecations
153+
154+
The following APIs have been deprecated and are due for removal in a future release of React Native:
155+
156+
- **`InitializeCore`**: `'react-native/Libraries/Core/InitializeCore'` is deprecated. Use `'react-native/setup-env'` instead.
157+
- **Prefixed background styles**: `experimental_backgroundSize`, `experimental_backgroundPosition` and `experimental_backgroundRepeat` are deprecated in favour of their unprefixed names. The prefixed names still work as aliases.
158+
- **`InputAccessoryView`**: iOS only, deprecated as part of keeping core lean. `react-native-keyboard-controller`’s [`KeyboardStickyView`](https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/components/keyboard-sticky-view) is a cross-platform replacement. Nothing changes in 0.88 beyond a JSDoc tag and a one-time warning on import.
159+
- `ReactFragment.fabricEnabled`: the New Architecture is unconditionally enabled on this path, so the per-fragment override no longer does anything. Drop the argument and the matching builder call.
160+
- **`ReactImageManager` `String?` overloads**: `setDefaultSource` and `setLoadingIndicatorSource` now take a `Dynamic`. The `String?` versions still work but break under props 2.0, so pass the prop value through rather than pre-resolving it.
161+
162+
## Other Changes
163+
164+
### Runtime & Web Spec Alignment
165+
166+
- **Styles**: `backgroundSize`, `backgroundPosition` and `backgroundRepeat` lose their `experimental_` prefix and are now stable. The prefixed names still work.
167+
- **Runtime**: `RuntimeScheduler` clears pending tasks and rendering updates when a task throws.
168+
- **Runtime**: async `CallInvoker` work is buffered alongside callable module calls, so it no longer runs before the JS bundle is ready.
169+
170+
- **FileReader**: fires `loadstart`, throws `InvalidStateError` on overlapping reads and exposes `FileReader.error` as a `DOMException`, matching the web spec (544141efab).
171+
- **FileReader**: stays in the correct state after a read is aborted (e92816c5a5).
172+
- **Blob**: a `Blob` is retained while a native read is pending, so it is no longer collected mid-read (568eaa6b69).
173+
- **Blob**: fixed an intermittent iOS crash when deriving blob names for network responses (671705dfb1).
174+
- **i18n**: RTL is detected from the active locale rather than an arbitrary installed one (e46189e1e1).
175+
176+
### Rendering, Layout & Animation
177+
178+
- **iOS RTL text**: text now aligns right by default in RTL when `textAlign` is not set, matching Android ([1b92b02f99](https://github.com/react/react-native/commit/1b92b02f99)).
179+
- **Radial gradients**: circle gradients now reject percentage radii, matching web behaviour ([5821fcaf5d](https://github.com/react/react-native/commit/5821fcaf5d)).
180+
181+
- **Animated**: `addListener` fires again for natively driven values derived with `add`, `subtract`, `multiply`, `divide`, `modulo`, `diffClamp` or `interpolate`.
182+
- **ScrollView**: `maintainVisibleContentPosition` holds position through rapid data updates (5cb65244dc).
183+
- **ScrollView**: programmatic scrolls no longer cancel active touches in enclosing scroll views (06eb1fefab).
184+
- **ScrollView**: recycled scroll views no longer keep the previous automatic keyboard inset behaviour (e0aa7a8b0a).
185+
- **Image**: `getSize()` and `getSizeWithHeaders()` accept `data:` URIs (8cfde6d083).
186+
- **Image**: source headers survive `crossOrigin` and `referrerPolicy` (08c7781e5a).
187+
- **Image**: fixed a crash when `borderRadius` is a percentage (f2a250ad89).
188+
- **Image**: `aria-*` state props are no longer ignored when `accessibilityState` is also set (c3caea9b5e).
189+
- **Renderer**: fixed an `IllegalStateException` in `SurfaceMountingManager.removeViewAt` and view registry entries being lost (3f553d76bc, d6a5f159c6).
190+
- **Renderer**: recycled iOS views clear `UIView.hidden` correctly (711a9a5e07).
191+
- **Renderer**: missing native component registrations are logged on both platforms (ef28a2c9d5).
192+
193+
### TypeScript & JavaScript API
194+
195+
- **Module augmentation**: Additional generated props and style types can now be extended via module augmentation, widening compatibility with styling libraries.
196+
- Added declarations for `requestIdleCallback`/`cancelIdleCallback`, `LogBox.isInstalled()`/`clearAllLogs()`, `FlatList`'s `strictMode` prop and `VirtualizedList`'s `ListItemComponent`.
197+
198+
### Infrastructure & Dependencies
199+
200+
- **React** 19.3.0 is synced into React Native.
201+
- **Metro** moves to 0.87, with the minimum bumped to 0.87.1 so upgrading projects resolve the same Metro as freshly created ones.
202+
- **Hermes** moves to 260318099.0.4.
203+
204+
### iOS
205+
206+
- **Assets**: images can be served from an asset catalog by setting `RCTUseAssetCatalog` in the app's `Info.plist`. It is off by default.
207+
- **CocoaPods**: a `React-cxxstableapi` dependency is added to third-party New Architecture pods so they can resolve React Native's C++ API.
208+
- **Codegen**: no longer crawls `node_modules` or follows symlinks when discovering components.
209+
210+
### Android
211+
212+
- **Networking**: the default `User-Agent` now includes the app name and version, matching iOS ([04e50d540d](https://github.com/react/react-native/commit/04e50d540d)). A server keying off the old default will see a different value.
213+
- **Renderer**: `androidx.collection` moves to 1.4.4, fixing view registry entries getting lost in `SurfaceMountingManager`.
214+
- **Network Inspection**: Network event reporting is exposed to third-party networking stacks as an unstable API.
215+
216+
### Developer Tools
217+
218+
- **React Native DevTools**: App screenshots via `Page.captureScreenshot` are available by default.
219+
- **React Native DevTools**: WebSocket inspection in the Network panel is on the [CANARY channel](/docs/releases/release-levels).
220+
221+
## Acknowledgements
222+
223+
React Native 0.88 contains 568 commits from 91 contributors. Thanks for all your hard work!
224+
225+
We want to send a special thank you to those community members that shipped significant contributions in this release.
226+
227+
- [Artur Morys-Magiera](https://github.com/artus9033) for SceneDelegate support
228+
- [Jakub Piasecki](https://github.com/j-piasecki) for the C++ Stable API work, guarding the renderer’s internal surfaces and marking what frameworks may rely on
229+
- [Christian Falch](https://github.com/chrfalch) for Swift Package Manager hardening
230+
- [Dawid Malecki](https://github.com/coado) for faster, more reliable dependency downloads from mirror and proxy caches
231+
- [Mathieu Acthernoene](https://github.com/zoontek) for making generated props and style types augmentable
232+
- [Rob Hogan](https://github.com/robhogan) for improvements to Metro
233+
234+
## Upgrade to 0.88
235+
236+
:::info
237+
238+
0.88 is now the latest stable version of React Native and 0.85.x moves to unsupported. For more information see [React Native's support policy](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md).
239+
240+
:::
241+
242+
#### Upgrading
243+
244+
Please use the [React Native Upgrade Helper](https://react-native-community.github.io/upgrade-helper/) to view code changes between React Native versions for existing projects, in addition to the [Upgrading docs](/docs/upgrading).
245+
246+
#### Create a new project
247+
248+
```sh
249+
npx @react-native-community/cli@latest init MyProject --version latest
250+
```
251+
252+
#### Expo
253+
254+
For Expo projects, React Native 0.88 will be available as part of the Expo SDK 58 releases.

0 commit comments

Comments
 (0)