Installation
Inertia is a thin wrapper around react-native-reanimated. The Reanimated install must complete first — Inertia is a peer to it, not a replacement.
Prerequisites
- Expo SDK
57(React Native0.86.x, React19.2.3) react-native-reanimated>=4.5.0 <4.6.0react-native-worklets>=0.10.0 <0.11.0— the worklet runtime Reanimated 4 is built on. It is a peer of both Reanimated and Inertia, so Yarn and pnpm will not install it for you.
Install Reanimated 4.5.3 or later in a development build or a store build. Reanimated 4.5.0 to 4.5.2 can show a view at its initial value after its animation ends: native keeps a settled value for 2 s only, and React holds the first-render value. When the JS thread does not read the settled value in that window (a stall of more than 1 s, a paused app, a native dialog), the next React commit writes the initial value back, so an entrance from opacity: 0 goes blank with no error. Reanimated 4.5.3 keeps the value until React has it (software-mansion/react-native-reanimated#9987). The fix is native, so it needs a new build, not an over-the-air update. Expo SDK 57 pins 4.5.1: add react-native-reanimated to expo.install.exclude in package.json, or expo install --check moves it back. Expo Go 57 runs 4.5.1 and cannot change, so a project in Expo Go keeps the defect.
Inertia targets one SDK band, not a floor, so SDK 57+ is not correct: the peer ranges stop below React Native 0.87 and below Reanimated 4.6, which the next SDK will carry.
The upper bounds are deliberate. Reanimated and react-native-worklets are version-locked to each other, and each pair works with one React Native band — Reanimated 4.5 needs worklets 0.10.x and React Native 0.83–0.86. A wider range would let a package manager pair a new Reanimated with an old worklets, a combination that cannot install at all. Supporting a second SDK needs a second release line, not a wider range.
Platforms
| Platform | Status |
|---|---|
| iOS | Supported |
| Android | Supported |
Web (react-native-web 0.21, through Expo) | Supported. The example app and the docs demo run on web. Tests ran in Chromium only. Safari and Firefox are not tested. |
| macOS (react-native-macos) | Not tested |
| Windows (react-native-windows) | Not tested |
| Electron | Not tested. Expo does not supply an Electron target. |
Inertia uses the same API on every supported platform. For web, add the web dependencies to an Expo app:
npx expo install react-dom react-native-web
Some behavior is different on web:
gesture.hoveredoperates on web only. On iOS and Android it does nothing. See Gestures.layoutIdmeasures the DOM rect withgetBoundingClientRect()on web. See Layout.- A static web export writes each element at its
initialvalues. Without the entrance guard, the page stays blank when the JavaScript bundle does not run. See Static export.
The adapter packages use the web support of their peer dependency:
@rootnative/inertia-gesturesoperates on web through the web support ofreact-native-gesture-handler.@rootnative/inertia-svgoperates on web through the web support ofreact-native-svg.@rootnative/inertia-gradientsoperates on web through the web component ofexpo-linear-gradient. On web, Reanimated can log a console error on each frame for this component. The gradient renders and animates correctly.
Which package has what
Read this before you install. The core package does not contain the gesture hooks, the gradient primitive, or the SVG primitives — each is a separate install. A swipe deck is one of the most common reasons to reach for this library, and useSwipe is not in the core package.
| You want | Package | Install |
|---|---|---|
Motion.* primitives, Presence, MotionConfig, every value-layer hook | @rootnative/inertia | core, always required |
useDrag, useSwipe, usePan | @rootnative/inertia-gestures | + react-native-gesture-handler |
| Animatable linear gradients | @rootnative/inertia-gradients | + expo-linear-gradient |
| Animatable SVG paths and shapes | @rootnative/inertia-svg | + react-native-svg |
useTouchDrag is the exception: it is a drag hook that lives in core, under the @rootnative/inertia/touch subpath, because PanResponder is built into React Native and needs no extra peer dependency. Reach for it when you want drag without taking react-native-gesture-handler, or when the drag needs keyboard accessibility.
Versions
All four packages ship in lockstep — the same version number, released together. Install the same version of every @rootnative/inertia* package you use, and each adapter requires a core version at or above its own.
Two things that mislead here:
- The
@rootnative/coreand@rootnative/componentspackages of RootNative UI are a different library on a different version line. That family being on0.0.0-alpha.xwhile this one is on0.0.xis expected, not a mismatch. npm viewshows analphadist-tag on these packages that is older thanlatest. It is a leftover from the prerelease line. Followlatest.
Install
Yarn is the default. Switch tabs for npm, pnpm, or Bun — your selection persists across the docs.
- Yarn
- npm
- pnpm
- Bun
yarn add @rootnative/inertia react-native-reanimated react-native-worklets
npm install @rootnative/inertia react-native-reanimated react-native-worklets
pnpm add @rootnative/inertia react-native-reanimated react-native-worklets
bun add @rootnative/inertia react-native-reanimated react-native-worklets
Then enable the worklets Babel plugin per the Reanimated install guide. The plugin is what transforms 'worklet'-marked functions into UI-thread code; without it, every animation crashes at runtime.
A typical babel.config.js for a managed Expo app:
module.exports = function (api) {
api.cache(true)
return {
presets: ['babel-preset-expo'],
plugins: ['react-native-worklets/plugin'],
}
}
The worklets plugin must be last in the plugins array. (react-native-reanimated/plugin still works in Reanimated 4 — it is a one-line shim that forwards to react-native-worklets/plugin — but the worklets name is the canonical one, and it's the one Inertia's own install check tells you to add.)
The plugin must run on node_modules too
@rootnative/inertia, react-native-reanimated and react-native-worklets all ship their 'worklet' directives untransformed. The plugin in the consumer's build turns them into UI-thread code. Metro runs Babel on node_modules, so an Expo or bare React Native app needs nothing more than the config above.
A web bundler without Metro (Vite, webpack, Electron, Tauri) skips node_modules by default. The build then succeeds, and no animation plays: every animated style stays at its first frame, and a production build shows no error. Inertia logs one console.error at the first Motion render in that case, in production too. Add the three packages to the plugin's include list. A Vite example with @rolldown/plugin-babel:
babel({
include: [
/src\/.*\.tsx?$/,
/node_modules\/(@rootnative|react-native-reanimated|react-native-worklets)\/.*\.m?js$/,
],
plugins: ['react-native-worklets/plugin'],
})
The equivalent for babel-loader in webpack is an include array with the same paths.
First animation
import { Motion } from '@rootnative/inertia'
export function FadeIn() {
return (
<Motion.View
initial={{ opacity: 0, translateY: 20 }}
animate={{ opacity: 1, translateY: 0 }}
transition={{
opacity: { type: 'timing', duration: 200 },
translateY: { type: 'spring', tension: 180, friction: 12 },
}}
/>
)
}
Try it live
The example app runs in the iframe below — tap any screen to interact with the same primitives you'd ship in your app.
Subpath imports
Each primitive is reachable directly so apps that animate one element don't pull in the rest:
import { MotionView } from '@rootnative/inertia/view'
import { MotionText } from '@rootnative/inertia/text'
import { MotionImage } from '@rootnative/inertia/image'
import { MotionPressable } from '@rootnative/inertia/pressable'
import { MotionScrollView } from '@rootnative/inertia/scroll-view'
@rootnative/inertia is sideEffects: false, so a bundler with tree-shaking enabled (Metro 0.79+, Webpack, Rollup) will drop primitives you don't reference. The named imports above tree-shake to within ~0.1 kB of the subpath equivalents, verified per-primitive in CI.
One caveat: the Motion namespace object cannot tree-shake. import { Motion } from '@rootnative/inertia' followed by Motion.View holds the whole namespace live (it's a literal object — bundlers can't eliminate property accesses). Use it for ergonomics; reach for import { MotionView } from '@rootnative/inertia' (or the subpath) when bundle size matters.
Optional adapter packages
Three sibling packages extend Inertia for capabilities that need extra peer dependencies. The core library has no required dependency on any of them — install only what you need.
Gestures (@rootnative/inertia-gestures)
Drag / pan / swipe hooks built on react-native-gesture-handler. Compose with any Motion.* primitive via <GestureDetector>.
- Yarn
- npm
- pnpm
- Bun
yarn add @rootnative/inertia-gestures react-native-gesture-handler
npm install @rootnative/inertia-gestures react-native-gesture-handler
pnpm add @rootnative/inertia-gestures react-native-gesture-handler
bun add @rootnative/inertia-gestures react-native-gesture-handler
Then follow the react-native-gesture-handler install guide — it needs <GestureHandlerRootView> near the root of your app. See Gestures adapter for the hooks.
Gradients (@rootnative/inertia-gradients)
MotionLinearGradient wraps expo-linear-gradient with animatable colors / start / end / locations. Works in bare React Native as well as Expo.
- Yarn
- npm
- pnpm
- Bun
yarn add @rootnative/inertia-gradients expo-linear-gradient
npm install @rootnative/inertia-gradients expo-linear-gradient
pnpm add @rootnative/inertia-gradients expo-linear-gradient
bun add @rootnative/inertia-gradients expo-linear-gradient
See Gradients for the primitive.
SVG (@rootnative/inertia-svg)
MotionPath wraps react-native-svg's <Path> with animatable d (path morphing on structurally-compatible paths), fill, stroke, strokeWidth, opacities, and strokeDashoffset. Works in bare React Native as well as Expo.
- Yarn
- npm
- pnpm
- Bun
yarn add @rootnative/inertia-svg react-native-svg
npm install @rootnative/inertia-svg react-native-svg
pnpm add @rootnative/inertia-svg react-native-svg
bun add @rootnative/inertia-svg react-native-svg
See SVG for the primitive.
Reduced motion
Inertia respects the OS reduce-motion accessibility setting by default — no extra wiring needed. To override the default for the whole app or a subtree, see MotionConfig.