github jpudysz/react-native-unistyles v3.7.0
Release v3.7.0

4 hours ago

What's Changed

A minor release with one breaking change: UnistylesRuntime.themeName now always returns the app theme. It also adds support for React Native 0.88's new style props and a Unistyles track in DevTools performance traces. Fixes cover keyboard insets in Android Modals, a duplicate copy of Unistyles in Expo bundles, Next.js server components, Reanimated styles in withUnistyles, and the Babel plugin's dependency tracking.

⚠️ Breaking change

  • UnistylesRuntime.themeName now always returns the app theme, like UnistylesRuntime.getTheme(). Before, inside a ScopedTheme it returned the scoped name only on renders that went through the ScopedTheme. When a component re-rendered on its own or read it in a callback, it got the app theme. UnistylesRuntime is global and can't read React Context, so it can't follow the scope reliably. To read the scoped theme name, use useUnistyles().rt.themeName or withUnistyles (#1346, closes #1295)
// before 3.7.0, inside a ScopedTheme
const themeName = UnistylesRuntime.themeName

// 3.7.0
const { rt } = useUnistyles()
const themeName = rt.themeName

✨ New

  • React Native 0.88 style props work on native and web: the object form of fontVariationSettings ({ wght: 900 }) and arrays for backgroundSize, backgroundPosition and backgroundRepeat. Before, the objects and arrays were dropped because the parser read them as breakpoints, and the string forms were lost after the first theme or breakpoint change (#1338)
  • Unistyles now has its own "Unistyles" track in React Native DevTools performance traces (React Native 0.86+, development builds only). It shows StyleSheet creation, dependency updates, shadow tree commits and refreshes, so you can read a slow theme switch straight from the Performance panel. Before, Unistyles commits showed up on the Renderer track as source: Unknown (#1332)

🎨 Themes and styles

  • rt.themeName in a StyleSheet inside a ScopedTheme stays scoped after styles are rebuilt (rotation, breakpoint or theme change). Before, it switched to the app theme while theme stayed scoped (#1346)
  • Adaptive themes keep following the OS after a ScopedTheme suspends (#1346)
  • After a theme change, a plain view sharing a style with a withUnistyles component (e.g. styles.root on both a wrapped ScrollView and a View) no longer shows the previous theme (#1335 by @rladnjs705, closes #1317)
  • withUnistyles(Animated.View) no longer breaks styling when its style array contains a useAnimatedStyle result, on native and web. This had been broken since 3.0.0 (#1345, closes #1309)
  • Styles created by spreading a unistyle into another StyleSheet.create (e.g. @rexovolt/react-native-markdown-display) no longer throw Value is undefined, expected an Object. This had been broken since 3.5.0 (#1341, closes #1337)

🧩 Babel plugin

  • Styles that return a ternary or a logical expression now track their dependencies on every branch. Before, they kept their first value, e.g. (compact) => compact ? { fontSize: 14 * rt.fontScale } : { fontSize: 18 * rt.fontScale } ignored font scale changes, even though debug: true said the dependency was tracked. With debug: true, the plugin now warns when it finds dependencies but can't attach them to the returned style (#1344, closes #1314)

🚇 Metro and bundling

  • In a default Expo app, Metro bundled two copies of Unistyles (lib/module and src), so ScopedTheme didn't reach children that mount later. react-native now comes before import in the package exports, so native resolves to a single copy. Web, Node/SSR and Jest resolve as before (#1307 by @budaestew, closes #1306)
  • With the experimental Metro integration, libraries that subclass a React Native class component (e.g. react-native-pdf extending FlatList) no longer crash on load with Object is not a constructor (#1340, closes #1324)

🤖 Android

  • rt.insets.ime now follows the keyboard inside a <Modal> on Android 11+ (React Native 0.86+). It resets to 0 when the Modal closes with the keyboard up. UnistylesRuntime.statusBar.setHidden and navigationBar.setHidden now apply to open Modals too, and useUnistyles().rt.insets.ime updates with the keyboard, like on iOS (#1331, closes #810)
    • Unistyles reads the React Native version at build time. If Gradle prints 🦄 Unistyles: React Native not found, set REACT_NATIVE_NODE_MODULES_DIR in your root build.gradle
  • The Bridgeless doesn't support CatalystInstance warning no longer appears on init, and Unistyles works with UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE. Android now uses the CallInvoker from the bindings installer, like iOS (#1330)

🌐 Web and SSR

  • Importing Unistyles from a Next.js App Router server component (the setup from the SSR guide) no longer throws createContext is not a function. This had been broken since 3.5.2 (#1301 by @bayasdev)
  • With CSSVars: false, setTheme no longer skips a real theme change, and StyleSheets outside a ScopedTheme no longer pick up a leftover scope (#1346)

🃏 Jest

  • Importing react-native-unistyles/web, /diagnostics or /components/native/* under the Jest mocks no longer throws StyleSheet.addChangeListener is not a function (#1342, closes #1339)
  • The withUnistyles mock now resolves uniProps and merges it like the real implementation. Before, the component got uniProps as a raw function prop (#1336 by @mayuriphad, closes #1318)

📚 Docs

  • react-native-edge-to-edge is deprecated. The docs now point to React Native's built-in edgeToEdgeEnabled=true Gradle property (#1326)

🧪 Internal

  • A Next.js App Router e2e runs in CI against the packed package, in both next dev and next start (#1302 by @bayasdev)
  • Example apps updated to React Native 0.88 and Expo SDK 58 (#1325)

❤️ Contributors

Thanks to everyone who sent a PR for this release:

And to those whose PRs and reports shaped the fixes:

Full Changelog: v3.6.0...v3.7.0

Don't miss a new react-native-unistyles release

NewReleases is sending notifications on new releases.