Pressable

Touches are not delivered as raw taps. React Native negotiates a responder: when a finger goes down, every view under it is asked in turn, from the outside in, whether it wants to claim the touch, and then again from the inside out whether it will actually take it. That negotiation is what lets a button inside a scroll view work correctly - the scroll view can claim a drag that moves too far, and a nested pressable wins the touch over its container when both would otherwise claim it. This package builds press, pressIn, pressOut and longPress on top of that same negotiation, the way React Native's own Pressability does, rather than on plain touch listeners that could not express any of it.

Import
import { Pressable, TouchableOpacity } from '@ng-native/components';
Template
<pressable><touchable-opacity> once they are in the component's imports

Pressable

<pressable> is the bare version of this: it renders a view and nothing else, but adds the press machinery. pressed is a public signal, reachable through a template reference for styling that depends on the press state without needing a class:

<pressable #p="pressable" [style.opacity]="p.pressed() ? 0.6 : 1" (press)="onTap()">
  <text>Tap me</text>
</pressable>

<touchable-opacity> is the same machinery wired to React Native's own default look: it fades to activeOpacity while pressed and eases back, using a CSS transition rather than a per-frame tween, with React Native's own asymmetric timings (150ms in, 250ms out).

Props

Every pressable exposes disabled, hitSlop, pressRetentionOffset (how far a finger may wander before the press is cancelled - separate from hitSlop, which is how far outside the view a touch may start), delayLongPress, delayPressIn, delayPressOut, minPressDuration (the pressed look is held at least this long even on the quickest tap), cancelable (whether a scrolling ancestor may take the gesture away mid-press) and, on Android, androidRipple for a native ripple.

Nested pressables

A pressable inside a pressable - a row with a delete button in it - needs nothing extra. The negotiation elects the innermost pressable that wants the touch, so a tap on the button presses the button and never the row. What does bubble past the button is the plain touch events, (touchStart) and (touchEnd), which are not negotiated; a handler that wants an ancestor not to see one calls $event.stopPropagation().

Composing pressability onto a component

A component that wants to be pressable rather than contain something pressable - a custom button, say - composes PressBehavior through hostDirectives instead of wrapping a <pressable>. That puts the whole responder negotiation on the component's own host node at the cost of one native view rather than two, and the component calls contributeAccessibility to tell the view primitive on that same host what role and state it should announce.

pressabledirective@ng-native/components
import { Pressable } from '@ng-native/components';and add Pressable to the component's imports

A view that responds to presses. RN's Pressable , with the same configuration: hit slop, retention offset, press-in and press-out delays, long press, and an Android ripple.

No public members.

touchable-opacitycomponent@ng-native/components
import { TouchableOpacity } from '@ng-native/components';and add TouchableOpacity to the component's imports

A pressable that dims while pressed, as RN's TouchableOpacity does.

Inputs

activeOpacity
number = 0.2

The opacity while pressed.

Angular components as native iOS and Android views, built and shipped with Expo.

An alpha. MIT licensed. Sponsor its development.

An independent project, not affiliated with or endorsed by Google, the Angular team or Expo. Angular is a trademark of Google LLC.