One Animation File for Web, iOS and Android: What Can Actually Be Shared
What one animation file can share across web, iOS and Android, what must adapt per platform, and how to test a cross-platform motion component.
Core Takeaway
One animation file can share the interaction model: states, transitions, timing, springs and the visual response to input. It cannot make every platform feel identical, because navigation, gestures, text and accessibility conventions differ. The practical approach is one authored source plus a runtime per platform, with small platform-specific overrides for behaviour users already expect.
What one file can own
A shared animation file is most useful when it owns the parts that are expensive to rebuild: the state machine, the spring values, the enter and exit paths and the mapping from input to visual state. Those are the parts that drift when each platform team reimplements the same button. The file becomes the reference for behaviour, not a promise that the pixels will be identical.
What must adapt
Platform conventions are not decoration. A back gesture on iOS, a system back action on Android and a browser history change on the web are different events even when they end in the same state. Text sizing, safe areas, haptics and focus behaviour also differ. A good cross-platform component exposes variants or inputs for those differences instead of forcing one behaviour everywhere.
- Navigation and back behaviour
- Gesture thresholds and edge regions
- Safe areas, text scaling and density
- Focus, keyboard and screen reader semantics
- Haptics and sound, where the platform supports them
How the runtime fits
The file needs a runtime on each target. ExodeUI provides runtime packages for React, Vue, Svelte, Angular, Solid, React Native, SwiftUI and Flutter, and the same .exode file can be played by each. Rive and dotLottie also have cross-platform players, with different feature support. The important question is not how many logos are on the runtime page. It is whether the specific states, inputs and events you need work on every platform you ship.
Design for the shared core
Start with the states every platform needs, then add platform variants only where the convention genuinely differs. A press state, a loading state and an error state can usually be shared. A swipe-to-dismiss threshold may need a different value on a phone and a desktop browser. Keep those differences named and documented so they do not become accidental drift.
Test the edges, not the demo
Test the interaction at the smallest and largest supported size, with text scaling on, with reduced motion on and with a slow network. Test interruption: start the action, navigate away, come back. Test the platform back gesture. A demo that plays once on a fast desktop proves very little.
When one file is the wrong choice
If the interaction depends heavily on a platform-only API, or if the component is used on one platform only, a shared file may add overhead without benefit. A native implementation can be simpler and faster. Use a shared file when the same interactive behaviour genuinely repeats across platforms and the cost of divergence is high. ExodeUI is one option for that case; we make it, so compare it with native code and the runtimes you already trust.
Key Principles to Remember
- Share states, transitions, springs and input mapping; adapt conventions per platform
- One file is a behaviour source, not a promise of identical pixels
- Expose variants for navigation, gestures, safe areas and accessibility differences
- Test interruption, text scaling, reduced motion and slow networks
- Use native code when the interaction is platform-specific or used on one platform only
Frequently Asked Questions
Sources
- Motion — Apple Human Interface Guidelines
- Motion overview — Material Design 3
- React Native documentation — Meta