skip to content

In React Native, what do the four View pointerEvents values do, and which lets taps pass through an overlay while its buttons work?

level: middleimportance: should knowfreq 30%

answer

  1. hit-testing, not visibility
  2. auto, none, box-none, box-only
  3. none excludes the whole subtree
  4. box-none: children only
  5. box-only: the view only

basics

~20 s

pointerEvents sets whether a React Native View and its children can be touch targets: 'auto' (both), 'none' (neither), 'box-none' (children only) and 'box-only' (the view only). An overlay uses 'box-none' so empty areas pass taps through.

solid answer

~40 s

`pointerEvents` decides which views can be the **target** of a touch; it changes hit-testing, not drawing. `'auto'` is normal behaviour. `'none'` means neither the view nor anything inside it can be a target, so touches fall through to whatever is underneath. `'box-none'` means the view itself is never a target but its children can be: the right choice for a full-screen `position: 'absolute'` layer holding a floating button above a scrolling poem, because taps and drags on the empty area reach the content below while the button still works. `'box-only'` is the reverse: the view can be a target but its children cannot, useful when a whole card should handle the press and inner controls must not. In 0.87 it is both a `View` prop and a style property.

code

tsx · 23 lines
tsx
import {Pressable, ScrollView, StyleSheet, Text, View} from 'react-native';

export function PoemScreen({poem, onAnnotate}: {poem: string; onAnnotate: () => void}) {
  return (
    <View style={styles.screen}>
      <ScrollView>
        <Text style={styles.poem}>{poem}</Text>
      </ScrollView>
      {/* The layer covers the screen but only its children take touches. */}
      <View style={StyleSheet.absoluteFill} pointerEvents="box-none">
        <Pressable style={styles.fab} onPress={onAnnotate}>
          <Text>Annotate</Text>
        </Pressable>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  screen: {flex: 1},
  poem: {fontSize: 18, lineHeight: 28, padding: 16},
  fab: {position: 'absolute', right: 16, bottom: 24, padding: 12},
});

go deeper

for a junior

Recall the four values and that pointerEvents controls whether a view can be touched, not whether it is visible.

for a middle

Explain how each value treats the view and its subtree, and why a transparent overlay still blocks touches until it gets box-none.

for a senior

Diagnose touch-swallowing overlays, choose box-none or box-only deliberately, and separate hit-testing problems from responder conflicts between gestures.

for a principal

Set conventions for floating layers and disabled regions across the app so overlays never silently block content, and review them as part of screen design.

## What pointerEvents controls When the user touches the screen, the platform performs **hit-testing**: it walks the view hierarchy to find the view under the finger that should receive the touch. `pointerEvents` lets a React Native `View` take itself, its children, or both out of that search. It does not change rendering: a view with `pointerEvents: 'none'` is still fully visible. It is accepted both as a **`View` prop** (`<View pointerEvents="box-none">`) and as a **style property** (`style={{pointerEvents: 'box-none'}}`). Components built on `View`, such as `Pressable`, accept it too, and `Text` has its own `pointerEvents` prop. ## The four values | Value | The view itself | Its descendants | Typical use | |---|---|---|---| | `'auto'` | can be a target | can be targets | normal behaviour | | `'none'` | never a target | never targets | decorative overlays, disabled regions | | `'box-none'` | never a target | can be targets | full-screen layers holding floating controls | | `'box-only'` | can be a target | never targets | a card that handles the press as one unit | Two details matter: - **`'none'` applies to the whole subtree.** A `Pressable` inside a `pointerEvents="none"` view cannot be pressed; touches go to whatever lies beneath the overlay. - **`'box-none'` is not the same as `'none'` on the parent and `'auto'` on children.** It is the one value that expresses "ignore my own empty area, keep my children interactive". ## The overlay scenario A poem reader shows the poem in a `ScrollView`. Above it, a floating **Annotate** button sits in the bottom-right corner. The easiest way to place it is a layer that covers the screen: 1. Render the `ScrollView`. 2. Render, after it, a `View` with `StyleSheet.absoluteFill` so it covers the screen, containing the button positioned at the bottom right. With the default `'auto'`, the layer is a valid touch target across the whole screen. Because it is on top, **it receives every touch**: the poem no longer scrolls, and inline links in the poem stop responding, even though the layer is transparent. Transparency has nothing to do with hit-testing. - `pointerEvents="none"` on the layer lets touches reach the poem, but also **disables the button**, because `'none'` covers descendants. - `pointerEvents="box-none"` on the layer makes its empty area transparent to touches while the **button stays pressable**. This is the fix. ## Where box-only helps `'box-only'` suits a component that must behave as one touchable unit even though it contains interactive children, for example a "locked" poem tile that shows a preview, including inline links, but should respond to any tap by opening a subscription screen. Setting `'box-only'` on the tile stops the inner links from ever receiving the touch, so the tile's own handler runs instead. ## Diagnosing a view that swallows touches When a region of the screen stops responding, the cause is usually a view on top of it that is a valid touch target: 1. Temporarily give suspected overlays a visible `backgroundColor` to see exactly what they cover. 2. Check the render order and `zIndex`: the overlay is often a later sibling or an absolutely positioned child of a parent that fills the screen. 3. Decide what the overlay needs: no interaction at all means `'none'`; interactive children but an inert background means `'box-none'`. 4. Re-test both the content below and the overlay's own controls, since fixing one by breaking the other is the usual regression. ## Common mistakes - **Using opacity to disable touches.** `opacity: 0` hides a view but leaves it a touch target; an invisible view can swallow taps. - **Putting `'none'` on a container with buttons in it**, then wondering why the buttons stopped working. - **Expecting `pointerEvents` to arbitrate between two handlers** that both want the same gesture. That negotiation, which view becomes the responder, is a different mechanism. - **Forgetting the stacking order.** Hit-testing starts from the top-most view, so a later sibling or a view with a higher `zIndex` is tested first.

  • In React Native, why does a fully transparent absolute overlay stop a ScrollView beneath it from scrolling?
    Hit-testing ignores colour and opacity. With the default `pointerEvents` of `'auto'`, the overlay is a valid target everywhere it covers, and because it is on top it is found first, so it takes the touches the `ScrollView` needed. Setting `pointerEvents` to `'box-none'`, or `'none'` if it has no interactive children, lets the touches reach the content below.
  • In React Native, is pointerEvents a View prop or a style property?
    Both. `View` accepts `pointerEvents` as a prop with the values `'auto'`, `'none'`, `'box-none'` and `'box-only'`, and the same values are accepted as a style property in `ViewStyle`. Either form controls hit-testing for that view; teams usually pick one form and use it consistently.

A box-none layer is a glass sheet with buttons glued to it: fingers pass straight through the glass to the page underneath, but anything glued on top can still be pressed.

saying these in an interview costs you the question

  • pointerEvents 'none' only affects the view itself; its buttons still receive taps.
  • A transparent or opacity 0 view never receives touches, so no extra prop is needed.
  • pointerEvents hides the view or changes how it is drawn.
  • 'box-only' lets touches pass through the view to its children.
  • pointerEvents decides which of two nested handlers wins the same gesture.