{"id":4799,"url":"https://github.com/wix-incubator/react-native-interactable","last_synced_at":"2025-10-18T02:57:38.237Z","repository":{"id":37734815,"uuid":"80166855","full_name":"wix-incubator/react-native-interactable","owner":"wix-incubator","description":"Experimental implementation of high performance interactable views in React Native","archived":false,"fork":false,"pushed_at":"2023-06-28T11:45:48.000Z","size":2945,"stargazers_count":5194,"open_issues_count":89,"forks_count":513,"subscribers_count":342,"default_branch":"master","last_synced_at":"2025-05-02T07:07:47.503Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wix-incubator.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-01-26T23:46:24.000Z","updated_at":"2025-04-08T17:42:56.000Z","dependencies_parsed_at":"2022-08-08T21:30:45.317Z","dependency_job_id":"8cffe4b7-2f4c-4ccd-b6d2-2f9ec1638ed1","html_url":"https://github.com/wix-incubator/react-native-interactable","commit_stats":{"total_commits":294,"total_committers":50,"mean_commits":5.88,"dds":0.6666666666666667,"last_synced_commit":"5ea6b0f3d13b3a9169fab58e84c6736471f0b83a"},"previous_names":["wix/react-native-interactable"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wix-incubator%2Freact-native-interactable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wix-incubator%2Freact-native-interactable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wix-incubator%2Freact-native-interactable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wix-incubator%2Freact-native-interactable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wix-incubator","download_url":"https://codeload.github.com/wix-incubator/react-native-interactable/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254129529,"owners_count":22019628,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-01-05T20:17:24.547Z","updated_at":"2025-10-18T02:57:33.186Z","avatar_url":"https://github.com/wix-incubator.png","language":"JavaScript","funding_links":[],"categories":["Components","JavaScript"],"sub_categories":["Animation"],"readme":"\u003cimg src=\"http://i.imgur.com/ErA2GQo.gif\" width=200 /\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u003cimg src=\"http://i.imgur.com/pH6oB5D.gif\" width=200 /\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u003cimg src=\"http://i.imgur.com/J5l2Qvq.gif\" width=200 /\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u003cimg src=\"http://i.imgur.com/dWFYZBG.gif\" width=200 /\u003e\n\n# Interactable\n\u003e react-native-interactable\n\n\u003cbr\u003e\n\n[![NPM Version](https://img.shields.io/npm/v/react-native-interactable.svg?style=flat)](https://www.npmjs.com/package/react-native-interactable)\n[![Build Status](https://img.shields.io/jenkins/s/http/jenkins-oss.wixpress.com:8080/job/multi-react-native-interactable-master.svg)](https://jenkins-oss.wixpress.com/job/multi-react-native-interactable-master/)\n[![NPM Downloads](https://img.shields.io/npm/dm/react-native-interactable.svg?style=flat)](https://www.npmjs.com/package/react-native-interactable)\n\n### LOOKING FOR A MAINTAINER\n\nWe love this project, but currently we don’t have enough time to work on it. So we are looking for a maintainer. If you have enough time and knowledge and want to become one - please let us know (levv@wix.com)\n\n\u003cbr\u003e\n\n### Description\n\n* [Installation](#installation)\n* [Example](#example)\n* [Usage](#usage)\n* [Implementation Details](#implementation-details)\n\n\u003cbr\u003e\nThis is an experimental implementation of a declarative API for handling fluid user interactions with views at 60 FPS in React Native. Here are some example use-cases for views that users can interact with:\n\n* **Swipeable card** (a la Google Now) springing into place unless swiped away with enough force\n* **Drawer** snapping between closed and open with buttons appearing gradually as it's being dragged\n* **Collapsible header** that snaps to a smaller size as the content below is being scrolled\n* **Chat heads** (a la Facebook Messenger) that can be dragged around but snap to corners of the screen\n\nAll of these use-cases have views that continuously interact with the user's gestures. These interactions are normally physical in nature, having properties like springiness, friction, elasticity and damping. In order to feel natural on a touch device they need to run at 60 FPS.\n\n### Why is this challenging?\n\nThe async nature of the React Native bridge incurs an inherent performance penalty. This traditionally prevents JavaScript code from running at high framerates. One of the most noticeable challenges is animations in JavaScript, which aren't guaranteed to run at 60 FPS.\n\nModern animation libraries for React Native, like [Animated](https://facebook.github.io/react-native/docs/animated.html), tackle this challenge with a declarative approach. In order to minimize passes over the bridge, animations are only declared in JavaScript but executed by a native driver on the other side - in 60 FPS.\n\nFluid user interactions take this a step further than animations. Interactions require UI to continuously react to the user's gestures. This library is designed to support complex physical interactions with ease, using a full-fledged physics engine to drive the interaction on the native side.\n\n### Why is it named interactable?\n\nFirst off, we are aware that *interactable* isn't a real word. The correct form is *interactive* but this has connotation that isn't necessarily related to physical interactions. Similar to `Animated.View`, we wanted to have `Interactable.View` - meaning a view you can interact with. And hey, [Unity](https://docs.unity3d.com/ScriptReference/UI.Selectable-interactable.html) did it too.\n\n\u003cbr\u003e\n\n## Installation\n\n**Requires RN 0.40 and above.**\n\n* Install the package from npm\n\n```\nnpm install react-native-interactable --save\n```\n\n* Link the native library to your project\n\n```\nreact-native link react-native-interactable\n```\n\nNote: instead of linking automatically you can also link manually according to these [instructions](http://facebook.github.io/react-native/docs/linking-libraries-ios.html#manual-linking)\n\n```\nnode_modules/react-native-interactable/ios/Interactable.xcodeproj\n```\n\n**Manually link via Cocoa Pods (iOS)**\n\n* Add the following to your `Podfile` and run `pod update`:\n\n```\npod 'Interactable', :path =\u003e '../node_modules/react-native-interactable'\n```\n\n\u003cbr\u003e\n\n## Example\n\n\u003cbr\u003e\u003cbr\u003eThe [playground](https://github.com/wix/react-native-interactable/tree/master/playground) project has few use-cases implemented like: *swipeable card*, *drawer*, *collapsible header* and *chat heads* under the \"Basic examples\" section. It's simplistic but easy to learn from.\n\u003cbr\u003e\u003cbr\u003eUnder the \"Real life example\" you'll find more complex demonstrations. They're harder to learn from, but they're cool to watch. More info about the [UX inspirations](https://github.com/wix/react-native-interactable/blob/master/UX-INSPIRATIONS.md) for the demo app.\n\n* **Build and run the example project**\nTo see the library in action, clone the repo and run the playground from the root folder:\u003cbr\u003e\n```\n  npm start\n  npm run ios\n```\n\u003cbr\u003e\u003cbr\u003e*Note: It's recommended to experience it on a [real device](http://facebook.github.io/react-native/docs/running-on-device.html) and not on a simulator. The simulator has poor performance so the framerate isn't like the real thing.*\n\u003cbr\u003e\u003cbr\u003e\n\n\n## Usage\n\nThe core of this library is the `Interactable.View` component, used to wrap views you want to interact with:\n\n```jsx\nimport Interactable from 'react-native-interactable';\n\n\u003cInteractable.View\n  horizontalOnly={true}\n  snapPoints={[{x: 0}, {x: -200}]}\n  onSnap={this.onDrawerSnap}\u003e\n\n  // the view that you wrap here will now support interactions\n\n\u003c/Interactable.View\u003e\n```\n\u003cbr\u003e\n\n### `Interactable.View` Props\n\n[Click here for the full reference for all props](https://github.com/wix/react-native-interactable/blob/master/PROPS.md)\n\n* [`snapPoints`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#snappoints-array-of-points) - a list of points the view will snap to after being dragged by the user\n\n```jsx\nsnapPoints={[{x: 0}, {x: -200}]}\n```\n\n* [`springPoints`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#springpoints-array-of-points) - connect the view's center to a group of constant springs\n\n```jsx\nspringPoints={[{x: 0, tension: 6000, damping: 0.5, influenceArea: {left: 0}}]}\n```\n\n* [`gravityPoints`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#gravitypoints-array-of-points) - attract/repel the view's center with a group of constant gravity wells\n\n```jsx\ngravityPoints={[{x: 0, y: 0, strength: 8000, falloff: 40, damping: 0.5}]}\n```\n\n* [`frictionAreas`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#frictionareas-array-of-areas) - add friction to the view's movement with a group of friction regions\n\n```jsx\nfrictionAreas={[{damping: 0.5, influenceArea: {top: 0}}]}\n```\n\n* [`alertAreas`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#alertareas-array-of-areas) - send alert event when the view's center enters/leaves any region within the group\n\n```jsx\nalertAreas={[{id: 'myArea', influenceArea: {top: 0}}]}\n```\n\n* [`horizontalOnly`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#horizontalonly-boolean) - whether the view should be locked to horizontal movement only\n\n```jsx\nhorizontalOnly={true}\n```\n\n* [`startOnFront`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#startOnFront-boolean) - [ANDROID ONLY] whether the view should call `bringToFront`\n\n```jsx\nstartOnFront\n```\n\n* [`verticalOnly`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#verticalonly-boolean) - whether the view should be locked to vertical movement only\n\n```jsx\nverticalOnly={true}\n```\n\n* [`boundaries`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#boundaries-object) - limits to movement relative to the view's center (after initial layout)\n\n```jsx\nboundaries={{left: -100, right: 100, bounce: 0.5}}\n```\n\n* [`onSnap`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#onsnap-function) - a function called whenever the view finishes snapping to a `snapPoints` point (after dragging)\n\n```jsx\nonSnap={this.onDrawerSnap}\n```\n\n* [`onSnapStart`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#onsnapstart-function) - a function called whenever the view starts snapping to a `snapPoints` point (after dragging)\n\n```jsx\nonSnapStart={this.onDrawerSnapStart}\n```\n\n* [`onStop`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#onstop-function) - a function called whenever the interaction stops (views freeze momentarily)\n\n```jsx\nonStop={this.onStopInteraction}\n```\n\n* [`onDrag`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#ondrag-function) - a function called whenever the user starts or stops dragging the view\n\n```jsx\nonDrag={this.onDragEvent}\n```\n\n* [`onAlert`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#onalert-function) - a function called whenever the view's center enters/leaves an alert area\n\n```jsx\nonAlert={this.onAlertEvent}\n```\n\n* [`dragEnabled`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#dragenabled-boolean) - whether the user can drag the view or not\n\n```jsx\ndragEnabled={true}\n```\n\n* [`dragWithSpring`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#dragwithspring-object) - specify to make dragging behavior of the view occur using a spring\n\n```jsx\ndragWithSpring={{tension: 2000, damping: 0.5}}\n```\n\n* [`dragToss`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#dragtoss-number) - time in seconds the view is allowed to be tossed before snapping to a point\n\n```jsx\ndragToss={0.1}\n```\n\n* [`animatedValueX`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#animatedvaluex-animatedvalue) - [`Animated.Value`](https://facebook.github.io/react-native/docs/animated.html#animatedvalue) that will contain the delta from the center as the view moves (x axis)\n\n```jsx\nanimatedValueX={this._deltaX}\n```\n\n* [`animatedValueY`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#animatedvaluey-animatedvalue) - [`Animated.Value`](https://facebook.github.io/react-native/docs/animated.html#animatedvalue) that will contain the delta from the center as the view moves (y axis)\n\n```jsx\nanimatedValueY={this._deltaY}\n```\n\n* [`animatedNativeDriver`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#animatednativedriver-boolean) - whether integration with [Animated](https://facebook.github.io/react-native/docs/animated.html) should use native driver\n\n```jsx\nanimatedNativeDriver={false}\n```\n\n* [`initialPosition`](https://github.com/wix/react-native-interactable/blob/master/PROPS.md#initialposition-point) - used to initialize the view's position to a position different than it's original center\n\n```jsx\ninitialPosition={{x: -140, y: -280}}\n```\n\n\u003cbr\u003e\n\n### `Interactable.View` Methods\n\n##### `setVelocity(params)` - used to imperatively set the view's velocity in order to move it around\n\n```jsx\ninstance.setVelocity({x: 2000});\n```\n\nTakes a single argument, which is a params object containing:\n * `x` - The horizontal velocity. Optional.\n * `y` - The vertical velocity. Optional.\n\n ##### `snapTo(params)` - used to imperatively cause the view to snap to one of its snap points\n\n ```jsx\n instance.snapTo({index: 2});\n ```\n\n Takes a single argument, which is a params object containing:\n  * `index` - The index of the snap point in the `snapPoints` array. Optional.\n\n##### `changePosition(params)` - used to imperatively set the view's position\n\n```jsx\ninstance.changePosition({x: 120, y: 40});\n```\n\nTakes a single argument, which is a params object containing:\n * `x` - The x coordinate.\n * `y` - The y coordinate.\n\n\u003cbr\u003e\n\n##### `bringToFront()` - bring view to front (Android Only)\n\n```jsx\ninstance.bringToFront();\n```\n\n## Animating other views according to `Interactable.View` position\n\nThis library is integrated with the [Animated](https://facebook.github.io/react-native/docs/animated.html) library in order to support performant animations of other views according to the movement of the `Interactable.View`.\n\nConsider the following use-cases:\n\n* Buttons that appear using a fade \u0026 scale animation under a drawer as it's being dragged ([example](https://github.com/wix/react-native-interactable/blob/b72eff0649b48dd50548593e5ecfe4c42b026a02/example/src/IconDrawer.js#L44))\n* Image in a collapsible header that scales as it's snapped between states ([example](https://github.com/wix/react-native-interactable/blob/b72eff0649b48dd50548593e5ecfe4c42b026a02/example/src/CollapsingHeader.js#L15))\n\nIn these use-cases, we have views different from the one the user is interacting with, that animate according to the interactive view's position. Since [Animated](https://facebook.github.io/react-native/docs/animated.html) library uses [`Animated.Value`](https://facebook.github.io/react-native/docs/animated.html#animatedvalue) to animate view properties, we support setting the value of an `Animated.Value` instance according to position of the interactable view. The `Animated.Value` will contain the delta between the `Interactable.View` original center and new center. This can be done separately on the X axis and Y axis.\n\nAfter setting this up, use [Animated](https://facebook.github.io/react-native/docs/animated.html) to declaratively define [interpolations](https://facebook.github.io/react-native/docs/animated.html#interpolate) of the `Animated.Value` to various animatable view properties like opacity, scale, rotation, translateX and translateY:\n\n```jsx\nthis._deltaY = new Animated.Value(0);\n\n\u003cAnimated.View style={{\n  transform: [{\n    scale: this._deltaY.interpolate({\n      inputRange: [-150, -150, 0, 0],\n      outputRange: [0.3, 0.3, 1, 1]\n    })\n  }]\n}}\u003e\n  ...\n\u003c/Animated.View\u003e\n\n\u003cInteractable.View\n  verticalOnly={true}\n  snapPoints={[{y: 0}, {y: -150}]}\n  animatedValueY={this._deltaY}\n\u003e\n  ...\n\u003c/Interactable.View\u003e\n```\n\n\u003cbr\u003e\n\n## Implementation Details\n\nOriginally, the iOS implementation relied on [UIKit Dynamics](https://developer.apple.com/reference/uikit/uidynamicanimator) - a powerful native animation engine for physical interactions. A physics engine is required in order to make the interaction life-like. Consider the action of tossing a view connected via a spring to a snap point. A simple native [spring animation](https://developer.apple.com/reference/uikit/uiview/1622594-animatewithduration) will not be enough to take the initial velocity vector into account.\n\nAt some point, UIKit Dynamics was dropped in favor of a home-brewed physics implementation in order to provide more control over the behaviors. This also paved the way for the Android port since there's no parallel to UIKit Dynamics for Android. The home-brewed physics engine was straightforward to port from Objective-C to Java and is now part of this library.\n\n## Contributing\n\nIf you are interested in the project, have feedback or want to contribute don't hesitate to contact me. I'm particularly interested in ideas on how to expand the declarative API for more use-cases and suggestions on how to improve performance. PRs are always welcome.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwix-incubator%2Freact-native-interactable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwix-incubator%2Freact-native-interactable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwix-incubator%2Freact-native-interactable/lists"}