dd-sdk-reactnative icon indicating copy to clipboard operation
dd-sdk-reactnative copied to clipboard

Using Pressable component does not add TAP action

Open imalgrab opened this issue 2 months ago • 4 comments

Describe the bug

We wanted to add accessibilityLabels to pressable components in our app and some of the UI elements from React Native Elements do add RUM TAP actions when pressed but when pressing React Native's <Pressable/> component with accessibilityLabel set nothing is added.

Reproduction steps

  1. Set up DD with user interactions tracking and debug level logs.
  2. Create a RN <Pressable/> component, set its content and onPress handler. Add accessibilityLabel prop.
  3. Tap the button
  4. No logs appear after tap.

SDK logs

No response

Expected behavior

No response

Affected SDK versions

2.12.1

Latest working SDK version

2.12.1

Did you confirm if the latest SDK version fixes the bug?

No

Integration Methods

NPM

React Native Version

0.76.9

Package.json Contents

"dependencies": {
    "@bam.tech/react-native-image-resizer": "3.0.7",
    "@datadog/mobile-react-native": "^2.12.1",
    "@datadog/mobile-react-navigation": "^2.12.1",
    "@emotion/react": "^11.14.0",
    "@emotion/styled": "^11.14.0",
    "@expo/vector-icons": "^14.0.3",
    "@gorhom/bottom-sheet": "^5.1.4",
    "@hookform/devtools": "^4.3.1",
    "@mui/icons-material": "^6.4.1",
    "@mui/material": "^6.4.1",
    "@mui/x-date-pickers": "^7.24.0",
    "@notifee/react-native": "7.8.2",
    "@react-native-async-storage/async-storage": "1.23.1",
    "@react-native-clipboard/clipboard": "^1.16.1",
    "@react-native-community/cli": "15.0.1",
    "@react-native-community/netinfo": "11.4.1",
    "@react-native-cookies/cookies": "^6.2.1",
    "@react-native-firebase/analytics": "19.2.2",
    "@react-native-firebase/app": "19.2.2",
    "@react-native-firebase/crashlytics": "19.2.2",
    "@react-native-firebase/messaging": "19.2.2",
    "@react-native-firebase/perf": "19.2.2",
    "@react-navigation/bottom-tabs": "6.5.20",
    "@react-navigation/drawer": "6.6.15",
    "@react-navigation/material-top-tabs": "6.6.13",
    "@react-navigation/native": "6.1.17",
    "@react-navigation/native-stack": "6.9.26",
    "@react-navigation/stack": "6.3.29",
    "@reduxjs/toolkit": "2.8.2",
    "@rneui/base": "^4.0.0-rc.8",
    "@rneui/themed": "^4.0.0-rc.8",
    "@sendbird/chat": "^4.17.4",
    "@sendbird/uikit-react-native": "3.9.4",
    "@types/react-dom": "~18.3.1",
    "date-fns": "4.1.0",
    "date-fns-tz": "3.2.0",
    "dotenv": "^16.0.3",
    "emoji-picker-react": "^4.12.2",
    "expo": "~52.0.46",
    "expo-application": "~6.0.2",
    "expo-asset": "~11.0.5",
    "expo-av": "~15.0.2",
    "expo-build-properties": "~0.13.3",
    "expo-constants": "~17.0.8",
    "expo-dev-client": "~5.0.20",
    "expo-device": "~7.0.3",
    "expo-document-picker": "~13.0.3",
    "expo-file-system": "~18.0.12",
    "expo-font": "~13.0.4",
    "expo-image": "~2.0.7",
    "expo-image-picker": "~16.0.6",
    "expo-linear-gradient": "~14.0.2",
    "expo-linking": "~7.0.5",
    "expo-local-authentication": "~15.0.2",
    "expo-localization": "~16.0.1",
    "expo-location": "~18.0.10",
    "expo-media-library": "~17.0.6",
    "expo-secure-store": "~14.0.1",
    "expo-splash-screen": "~0.29.24",
    "expo-status-bar": "~2.0.1",
    "expo-system-ui": "~4.0.9",
    "expo-web-browser": "~14.0.2",
    "fast-text-encoding": "^1.0.6",
    "iban": "^0.0.14",
    "material-react-table": "^3.2.1",
    "postinstall-postinstall": "^2.1.0",
    "prettier": "^3.0.3",
    "react": "18.3.1",
    "react-dom": "^18.2.0",
    "react-hook-form": "^7.58.1",
    "react-native": "0.76.9",
    "react-native-calendars": "^1.1312.0",
    "react-native-create-thumbnail": "^2.0.1",
    "react-native-date-picker": "^5.0.12",
    "react-native-dotenv": "3.4.11",
    "react-native-element-dropdown": "^2.12.4",
    "react-native-file-access": "3.1.0",
    "react-native-gesture-handler": "~2.20.2",
    "react-native-keyboard-controller": "^1.17.1",
    "react-native-mime-types": "^2.5.0",
    "react-native-mmkv": "2.12.2",
    "react-native-modal": "^13.0.1",
    "react-native-pager-view": "6.5.1",
    "react-native-permissions": "^5.4.0",
    "react-native-reanimated": "~3.16.1",
    "react-native-safe-area-context": "4.12.0",
    "react-native-screens": "~4.4.0",
    "react-native-svg": "15.8.0",
    "react-native-tab-view": "3.5.2",
    "react-native-toast-message": "^2.3.0",
    "react-native-url-polyfill": "^2.0.0",
    "react-native-uuid": "^2.0.1",
    "react-native-vector-icons": "^10.2.0",
    "react-native-video": "^6.13.0",
    "react-native-web": "0.0.0-dee1467a3",
    "react-redux": "^8.0.2",
    "redux-persist": "^6.0.0",
    "redux-persist-expo-securestore": "^2.0.0",
    "rn-emoji-keyboard": "^1.7.0"
  },
  "devDependencies": {
    "@babel/core": "^7.25.2",
    "@babel/preset-env": "^7.25.3",
    "@babel/runtime": "^7.25.0",
    "@config-plugins/detox": "^7.0.0",
    "@datadog/datadog-ci": "^4.0.2",
    "@expo/metro-runtime": "~4.0.1",
    "@react-native-community/datetimepicker": "8.2.0",
    "@react-native-community/slider": "4.5.5",
    "@react-native/babel-preset": "0.76.9",
    "@storybook/addon-actions": "8.1.11",
    "@storybook/addon-controls": "^8.2.9",
    "@storybook/addon-essentials": "^8.2.9",
    "@storybook/addon-interactions": "^8.2.9",
    "@storybook/addon-links": "^8.2.9",
    "@storybook/addon-onboarding": "^8.2.9",
    "@storybook/addon-ondevice-actions": "^7.6.20",
    "@storybook/addon-ondevice-controls": "^7.6.20",
    "@storybook/addon-react-native-web": "^0.0.24",
    "@storybook/addon-webpack5-compiler-babel": "^3.0.3",
    "@storybook/blocks": "^8.2.9",
    "@storybook/react": "^8.2.9",
    "@storybook/react-native": "^7.6.20",
    "@storybook/react-native-server": "^6.5.8",
    "@storybook/react-webpack5": "^8.2.9",
    "@storybook/test": "^8.2.9",
    "@svgr/webpack": "^8.1.0",
    "@testing-library/dom": "^10.4.0",
    "@testing-library/react": "^16.3.0",
    "@testing-library/react-native": "^12.4.5",
    "@types/iban": "^0.0.35",
    "@types/jest": "^29.5.14",
    "@types/react": "18.3.12",
    "@types/react-native-video": "5.0.18",
    "@typescript-eslint/eslint-plugin": "^8.9.0",
    "@typescript-eslint/parser": "^8.9.0",
    "babel-jest": "^29.7.0",
    "babel-loader": "^8.2.5",
    "babel-plugin-inline-react-svg": "^2.0.1",
    "babel-plugin-module-resolver": "^5.0.2",
    "babel-plugin-react-native-web": "^0.19.10",
    "babel-plugin-transform-inline-environment-variables": "^0.4.4",
    "detox": "20.18.4",
    "eslint": "^8.48.0",
    "eslint-config-universe": "14.0.0",
    "eslint-plugin-import": "^2.30.0",
    "eslint-plugin-storybook": "^0.8.0",
    "http-proxy-middleware": "^3.0.5",
    "jest": "^29.7.0",
    "jest-circus": "^29.7.0",
    "jest-expo": "~52.0.6",
    "msw": "^2.7.3",
    "patch-package": "^8.0.0",
    "react-native-svg-transformer": "^1.0.0",
    "storybook": "^8.2.9",
    "ts-jest": "^29.0.3",
    "typescript": "^5.1.6"

iOS Setup

No response

Android Setup

No response

Device Information

iPhone 16 Pro Max, iOS simulator (18.4)

Other relevant information

No response

imalgrab avatar Nov 07 '25 08:11 imalgrab

Hey @imalgrab, thanks for reaching out, you can add that through our react-native-babel-plugin, you can configure it like this:

// babel.config.js
module.exports = {
  presets: ['YOUR_PRESETS'],
  plugins: [
    [
      '@datadog/mobile-react-native-babel-plugin',
      {
        components: {
          useContent: true,
          useNamePrefix: true,
          tracked: [
            {
              name: 'CustomButton',
              contentProp: 'text' // use this if the text on the components is set through a Prop
              handlers: [{event: 'onPress', action: 'TAP'}],
            },
          ],
        },
      },
    ],
  ],
};

Change the CustomButton to the name of the component you want to target.

Action tracking through the babel plugin is now the recommended way, the old way will be deprecated in the near future, so you should add the plugin to your project.

It also offers a lot more configuration options so you can add your custom components or components from third-party libraries as well. It also has other features like adding retrieving the text content of the UI if configured for that end, among other things.

cdn34dd avatar Nov 07 '25 15:11 cdn34dd

@cdn34dd This unfortunately did not work for me. What I tried:

  • installing the babel plugin and configuring the bable.config.js file:
    plugins: [
      [
        '@datadog/mobile-react-native-babel-plugin',
        {
          components: {
            useContent: true,
            useNamePrefix: true,
            tracked: [
              {
                name: 'RXButton',
                contentProp: 'label',
                handlers: [{ event: 'onPress', action: 'TAP' }],
              },
            ],
          },
        },
      ],
    ],  
    
    with the following component: <RXButton onPress={() => {}} label="Click Me" />
  • installing @babel/preset-typescript
  • setting accessibilityLabel and dd-action-name on Pressable and my custom components with the onPress prop

I'm using expo: 52.0.47 and react-native: 0.76.9

What, for some reason, did work is a combination of Link (from expo-router) and Pressable:

<Link href={viewAllLink} asChild>
  <Pressable
    accessibilityLabel={`View All ${title}`}
    accessibilityRole="button"
  >
    <Text>View All</Text>
  </Pressable>
</Link>

This gets reported as DATADOG: Adding RUM Action “View All Recent Payments” (TAP)

I don't really understand how DataDog selects components to report RUM events and there doesn't seem to be any relevant information in the docs except for a small paragraph. Even if the babel approach does work, it would be inconvenient to modify babel.config.js every time a new custom component is introduced.

Any help would be appreciated!

ANDREYDEN avatar Nov 11 '25 23:11 ANDREYDEN

@ANDREYDEN The goal with the babel plugin moving forward is to safely support more third-party libraries out of the box but given the number of UI packages available in the react-native, this is something that will take some time.

The plugin itself should be able to identify any custom components that are created using the pressables/buttons from the core react-native library, and for other components you can configure them in the babel.config.js, as mentioned before this will be improved in the following releases as more and more UI libraries are supported.

Can you be more specific on the issue you're having with Pressable ? If Pressable is imported from the react-native package and you use the babel plugin, there should be no configuration needed, it should just work. If you import it from some other library you'll need to add it to the babel configuration file.

cdn34dd avatar Nov 12 '25 11:11 cdn34dd

@cdn34dd Thanks for clarifying, this makes more sense! Could you please expand on the logic of how components are chosen to emit RUM actions? Maybe a link to the source code?

Here's my Pressable issue: in the following snippet the "Pressable Button" does not emit a RUM action while the "Link Button" one does.

import { Link } from 'expo-router';
import { Pressable, Text } from 'react-native';

export function TestComponent() {
  return (
    <>
      <Pressable
        onPress={() => {}}
        accessibilityLabel="Pressable Button"
        accessibilityRole="button"
      >
        <Text>Pressable Button</Text>
      </Pressable>

      <Link asChild href="/">
        <Pressable
          onPress={() => {}}
          accessibilityLabel="Link Button"
          accessibilityRole="button"
        >
          <Text>Link Button</Text>
        </Pressable>
      </Link>
    </>
  );
}

I simplified my babel.config.js to the following, since you mentioned that the plugin configuration shouldn't matter:

module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo', '@babel/preset-typescript'],
    plugins: ['@datadog/mobile-react-native-babel-plugin'],
  };
};

ANDREYDEN avatar Nov 12 '25 16:11 ANDREYDEN

Hey @ANDREYDEN , unfortunately I can't reproduce the issue you mention, I tried it just now and things seem to be working as intended. It may be something specific to your setup. Could you try to first use the latest version of the SDK, as some fixes were done to the plugin a few versions ago and also when you start metro could you please start it with yarn start --reset-cache to ensure that no caching issues are at play here ?

If that still does not work, I would ask you to create a simple sample app where the issue occurs so I can further debug it.

cdn34dd avatar Nov 17 '25 10:11 cdn34dd

@cdn34dd It's not clear to me what exactly was the cause, but after upgrading to Expo 54 and running the app with npx expo run:ios --clear-build-cache, the plugin is now working as intended:

  • I can see the Pressable reporting proper RUM actions
  • I can configure our RXButton (which is coming from an external package) to report RUM actions (using the babel configuration I posted above)

What is now not working is the "Link Button" from my previous example, but I'm guessing that the @datadog/mobile-react-native-babel-plugin doesn't have proper configuration for expo-router yet. I'll try to create some configuration for the Link component myself.

Another observation that I had is that RUM action recording works correctly when running a build of the app on a real device even without the babel plugin. I suppose it makes sense since the app is not running through a bundler anymore, but this was really my main concern from the start.

TL; DR; RUM actions will be correctly reported in production, but the bundler plugin configuration is needed to debug and reproduce these actions when running the app locally.

ANDREYDEN avatar Nov 19 '25 21:11 ANDREYDEN

@ANDREYDEN Great to hear that things are working now, I'll close this issue now, feel free to open another one if anything else comes up.

cdn34dd avatar Nov 20 '25 09:11 cdn34dd