Repository: PostHog/posthog-js-lite
Pull request #496: fix: survey modal closes when clicking inside the modal
Author: login: marandaneto
Created: 2025-05-07T09:15:23Z | Merged: 2025-05-07T09:49:23Z

## Problem

Closes https://github.com/PostHog/posthog-js-lite/issues/472

## Changes

<!-- What is changed and what information would be useful to a reviewer? -->

## Release info Sub-libraries affected

### Bump level

<!-- Please mark what level of change this is. -->

- [ ] Major
- [ ] Minor
- [X] Patch

### Libraries affected

<!-- Please mark which libraries will require a version bump. -->

- [ ] All of them
- [ ] posthog-web
- [ ] posthog-node
- [ ] posthog-ai
- [X] posthog-react-native

### Changelog notes

<!-- Add notes here that should be added to the changelogs. -->

- Added support for X



Diff:
diff --git a/posthog-core/src/index.ts b/posthog-core/src/index.ts
index 411eb7e1..038e53ce 100644
--- a/posthog-core/src/index.ts
+++ b/posthog-core/src/index.ts
@@ -1076,7 +1076,13 @@ export abstract class PostHogCoreStateless {
     }
 
     const body = options.body ? options.body : ''
-    const reqByteLength = Buffer.byteLength(body, STRING_FORMAT)
+    let reqByteLength = -1
+    try {
+      reqByteLength = Buffer.byteLength(body, STRING_FORMAT)
+    } catch {
+      const encoded = new TextEncoder().encode(body)
+      reqByteLength = encoded.length
+    }
 
     return await retriable(
       async () => {
diff --git a/posthog-react-native/CHANGELOG.md b/posthog-react-native/CHANGELOG.md
index af4f6181..76e8c5b4 100644
--- a/posthog-react-native/CHANGELOG.md
+++ b/posthog-react-native/CHANGELOG.md
@@ -1,8 +1,16 @@
 # Next
 
+# 3.15.2 – 2025-05-07
+
+## Fixed
+
+1. survey modal closes when clicking inside the modal
+
 # 3.15.1 – 2025-04-28
 
-1. fix: revert migration to rollup
+## Fixed
+
+1. revert migration to rollup
 
 # 3.15.0 – 2025-04-23
 
diff --git a/posthog-react-native/package.json b/posthog-react-native/package.json
index d313bb0e..344de0a8 100644
--- a/posthog-react-native/package.json
+++ b/posthog-react-native/package.json
@@ -1,6 +1,6 @@
 {
   "name": "posthog-react-native",
-  "version": "3.15.1",
+  "version": "3.15.2",
   "main": "lib/posthog-react-native/index.js",
   "files": [
     "lib/"
diff --git a/posthog-react-native/src/surveys/components/SurveyModal.tsx b/posthog-react-native/src/surveys/components/SurveyModal.tsx
index c349a96f..c47953e1 100644
--- a/posthog-react-native/src/surveys/components/SurveyModal.tsx
+++ b/posthog-react-native/src/surveys/components/SurveyModal.tsx
@@ -54,37 +54,36 @@ export function SurveyModal(props: SurveyModalProps): JSX.Element | null {
       >
         <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
           <View style={styles.modalBackdrop}>
-            <Pressable onPress={onClose} accessible={false}>
-              <View
-                style={[
-                  styles.modalContent,
-                  {
-                    borderColor: appearance.borderColor,
-                    backgroundColor: appearance.backgroundColor,
-                    marginBottom: insets.bottom + 10,
-                    marginHorizontal: 10,
-                  },
-                ]}
-              >
-                {!shouldShowConfirmation ? (
-                  <Questions survey={survey} appearance={appearance} onSubmit={() => setIsSurveySent(true)} />
-                ) : (
-                  <ConfirmationMessage
-                    appearance={appearance}
-                    header={appearance.thankYouMessageHeader}
-                    description={appearance.thankYouMessageDescription}
-                    contentType={
-                      appearance.thankYouMessageDescriptionContentType ?? SurveyQuestionDescriptionContentType.Text
-                    }
-                    onClose={onClose}
-                    isModal={true}
-                  />
-                )}
-                <View style={styles.topIconContainer}>
-                  <Cancel onPress={onClose} appearance={appearance} />
-                </View>
+            <Pressable style={StyleSheet.absoluteFill} onPress={onClose} accessible={false} />
+            <View
+              style={[
+                styles.modalContent,
+                {
+                  borderColor: appearance.borderColor,
+                  backgroundColor: appearance.backgroundColor,
+                  marginBottom: insets.bottom + 10,
+                  marginHorizontal: 10,
+                },
+              ]}
+            >
+              {!shouldShowConfirmation ? (
+                <Questions survey={survey} appearance={appearance} onSubmit={() => setIsSurveySent(true)} />
+              ) : (
+                <ConfirmationMessage
+                  appearance={appearance}
+                  header={appearance.thankYouMessageHeader}
+                  description={appearance.thankYouMessageDescription}
+                  contentType={
+                    appearance.thankYouMessageDescriptionContentType ?? SurveyQuestionDescriptionContentType.Text
+                  }
+                  onClose={onClose}
+                  isModal={true}
+                />
+              )}
+              <View style={styles.topIconContainer}>
+                <Cancel onPress={onClose} appearance={appearance} />
               </View>
-            </Pressable>
+            </View>
           </View>
         </TouchableWithoutFeedback>
       </KeyboardAvoidingView>


Reviews:
user: login: marandaneto
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-07T09:15:47Z
user: login: marandaneto
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-07T09:16:03Z
user: login: greptile-apps[bot]
body: 
## PR Summary

Fixed an issue in the React Native survey modal where clicking inside the modal would cause it to close unexpectedly, improving the usability of surveys across both mobile and web platforms.

- Restructured touch handling in `SurveyModal.tsx` by moving `Pressable` component outside modal content using `StyleSheet.absoluteFill`
- Added error handling for byte length calculation in `fetchWithRetry` method with TextEncoder fallback
- Updated version to 3.15.2 in package.json and documented fix in changelog
- Improved modal interaction behavior while maintaining backdrop dismiss functionality

<sub>4 file(s) reviewed, 2 comment(s)</sub>
<sub>[Edit PR Review Bot Settings](https://app.greptile.com/review/github) | [Greptile](https://greptile.com?utm_source=greptile_expert&utm_medium=github&utm_campaign=code_reviews&utm_content=posthog-js-lite_496)</sub>
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T09:16:20Z
user: login: ioannisj
body: Yeah, Pressable fix makes sense. Will modal content be rendered on top now though as expected? Any effect on keyboard avoidance? (on mobile now can't test) 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T09:49:21Z
user: login: rafaeelaudibert
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-06-04T23:41:53Z
user: login: rafaeelaudibert
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-06-04T23:42:01Z

Review comments:
diff_hunk: @@ -54,37 +54,36 @@ export function SurveyModal(props: SurveyModalProps): JSX.Element | null {
       >
         <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
           <View style={styles.modalBackdrop}>
-            <Pressable onPress={onClose} accessible={false}>
-              <View
-                style={[
-                  styles.modalContent,
-                  {
-                    borderColor: appearance.borderColor,
-                    backgroundColor: appearance.backgroundColor,
-                    marginBottom: insets.bottom + 10,
-                    marginHorizontal: 10,
-                  },
-                ]}
-              >
-                {!shouldShowConfirmation ? (
-                  <Questions survey={survey} appearance={appearance} onSubmit={() => setIsSurveySent(true)} />
-                ) : (
-                  <ConfirmationMessage
-                    appearance={appearance}
-                    header={appearance.thankYouMessageHeader}
-                    description={appearance.thankYouMessageDescription}
-                    contentType={
-                      appearance.thankYouMessageDescriptionContentType ?? SurveyQuestionDescriptionContentType.Text
-                    }
-                    onClose={onClose}
-                    isModal={true}
-                  />
-                )}
-                <View style={styles.topIconContainer}>
-                  <Cancel onPress={onClose} appearance={appearance} />
-                </View>
+            <Pressable style={StyleSheet.absoluteFill} onPress={onClose} accessible={false} />
path: posthog-react-native/src/surveys/components/SurveyModal.tsx
user: login: marandaneto
body: not wrapping the whole thing fixes it
created_at: 2025-05-07T09:15:47Z
author_association: MEMBER
diff_hunk: @@ -54,37 +54,36 @@ export function SurveyModal(props: SurveyModalProps): JSX.Element | null {
       >
         <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
           <View style={styles.modalBackdrop}>
-            <Pressable onPress={onClose} accessible={false}>
-              <View
-                style={[
-                  styles.modalContent,
-                  {
-                    borderColor: appearance.borderColor,
-                    backgroundColor: appearance.backgroundColor,
-                    marginBottom: insets.bottom + 10,
-                    marginHorizontal: 10,
-                  },
-                ]}
-              >
-                {!shouldShowConfirmation ? (
-                  <Questions survey={survey} appearance={appearance} onSubmit={() => setIsSurveySent(true)} />
-                ) : (
-                  <ConfirmationMessage
-                    appearance={appearance}
-                    header={appearance.thankYouMessageHeader}
-                    description={appearance.thankYouMessageDescription}
-                    contentType={
-                      appearance.thankYouMessageDescriptionContentType ?? SurveyQuestionDescriptionContentType.Text
-                    }
-                    onClose={onClose}
-                    isModal={true}
-                  />
-                )}
-                <View style={styles.topIconContainer}>
-                  <Cancel onPress={onClose} appearance={appearance} />
-                </View>
+            <Pressable style={StyleSheet.absoluteFill} onPress={onClose} accessible={false} />
path: posthog-react-native/src/surveys/components/SurveyModal.tsx
user: login: greptile-apps[bot]
body: logic: The Pressable with absoluteFill may still intercept touches on the modal content due to z-index layering. Consider adding `pointerEvents="box-none"` to prevent this.
created_at: 2025-05-07T09:15:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -54,37 +54,36 @@ export function SurveyModal(props: SurveyModalProps): JSX.Element | null {
       >
         <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
           <View style={styles.modalBackdrop}>
-            <Pressable onPress={onClose} accessible={false}>
-              <View
-                style={[
-                  styles.modalContent,
-                  {
-                    borderColor: appearance.borderColor,
-                    backgroundColor: appearance.backgroundColor,
-                    marginBottom: insets.bottom + 10,
-                    marginHorizontal: 10,
-                  },
-                ]}
-              >
-                {!shouldShowConfirmation ? (
-                  <Questions survey={survey} appearance={appearance} onSubmit={() => setIsSurveySent(true)} />
-                ) : (
-                  <ConfirmationMessage
-                    appearance={appearance}
-                    header={appearance.thankYouMessageHeader}
-                    description={appearance.thankYouMessageDescription}
-                    contentType={
-                      appearance.thankYouMessageDescriptionContentType ?? SurveyQuestionDescriptionContentType.Text
-                    }
-                    onClose={onClose}
-                    isModal={true}
-                  />
-                )}
-                <View style={styles.topIconContainer}>
-                  <Cancel onPress={onClose} appearance={appearance} />
-                </View>
+            <Pressable style={StyleSheet.absoluteFill} onPress={onClose} accessible={false} />
+            <View
+              style={[
+                styles.modalContent,
+                {
+                  borderColor: appearance.borderColor,
+                  backgroundColor: appearance.backgroundColor,
+                  marginBottom: insets.bottom + 10,
+                  marginHorizontal: 10,
path: posthog-react-native/src/surveys/components/SurveyModal.tsx
user: login: greptile-apps[bot]
body: style: marginHorizontal is set twice - both in styles.modalContent and inline styles. This could cause confusion.

```suggestion
                  marginBottom: insets.bottom + 10,
```
created_at: 2025-05-07T09:15:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1076,7 +1076,13 @@ export abstract class PostHogCoreStateless {
     }
 
     const body = options.body ? options.body : ''
-    const reqByteLength = Buffer.byteLength(body, STRING_FORMAT)
+    let reqByteLength = -1
+    try {
+      reqByteLength = Buffer.byteLength(body, STRING_FORMAT)
+    } catch {
+      const encoded = new TextEncoder().encode(body)
+      reqByteLength = encoded.length
+    }
path: posthog-core/src/index.ts
user: login: marandaneto
body: unrelated to PR title but fixing it anyway
Buffer is node only
created_at: 2025-05-07T09:16:03Z
author_association: MEMBER
diff_hunk: @@ -1076,7 +1076,13 @@ export abstract class PostHogCoreStateless {
     }
 
     const body = options.body ? options.body : ''
-    const reqByteLength = Buffer.byteLength(body, STRING_FORMAT)
+    let reqByteLength = -1
+    try {
+      reqByteLength = Buffer.byteLength(body, STRING_FORMAT)
+    } catch {
+      const encoded = new TextEncoder().encode(body)
+      reqByteLength = encoded.length
+    }
path: posthog-core/src/index.ts
user: login: rafaeelaudibert
body: Reported in https://github.com/PostHog/posthog-js-lite/issues/517, but because you didn't cut a new `posthog-web` version when you changed this, it's not live yet. Will release a new version tomorrow.
created_at: 2025-06-04T23:41:53Z
author_association: MEMBER
diff_hunk: @@ -1076,7 +1076,13 @@ export abstract class PostHogCoreStateless {
     }
 
     const body = options.body ? options.body : ''
-    const reqByteLength = Buffer.byteLength(body, STRING_FORMAT)
+    let reqByteLength = -1
+    try {
+      reqByteLength = Buffer.byteLength(body, STRING_FORMAT)
+    } catch {
+      const encoded = new TextEncoder().encode(body)
+      reqByteLength = encoded.length
+    }
path: posthog-core/src/index.ts
user: login: rafaeelaudibert
body: Thanks for the fix :)
created_at: 2025-06-04T23:42:01Z
author_association: MEMBER

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-07T09:16:59Z
body: **Size Change:** +467 B (+0.15%) 

**Total Size:** 316 kB

| Filename | Size | Change |
| :--- | :---: | :---: |
| `posthog-node/lib/edge/index.cjs` | 34.6 kB | +84 B (+0.24%) |
| `posthog-node/lib/edge/index.mjs` | 34.4 kB | +78 B (+0.23%) |
| `posthog-node/lib/node/index.cjs` | 39 kB | +84 B (+0.22%) |
| `posthog-node/lib/node/index.mjs` | 38.8 kB | +79 B (+0.2%) |
| `posthog-react-native/lib/posthog-core/src/index.js` | 14.6 kB | +46 B (+0.32%) |
| `posthog-react-native/lib/posthog-react-native/src/surveys/components/SurveyModal.js` | 1.6 kB | +10 B (+0.63%) |
| `posthog-web/lib/index.cjs` | 25.8 kB | +42 B (+0.16%) |
| `posthog-web/lib/index.mjs` | 25.7 kB | +44 B (+0.17%) |

<details><summary>ℹ️ <strong>View Unchanged</strong></summary>

| Filename | Size |
| :--- | :---: |
| `posthog-ai/lib/anthropic/index.cjs` | 2.81 kB |
| `posthog-ai/lib/anthropic/index.mjs` | 2.66 kB |
| `posthog-ai/lib/index.cjs` | 12.8 kB |
| `posthog-ai/lib/index.mjs` | 12.5 kB |
| `posthog-ai/lib/langchain/index.cjs` | 7.72 kB |
| `posthog-ai/lib/langchain/index.mjs` | 7.5 kB |
| `posthog-ai/lib/openai/index.cjs` | 2.71 kB |
| `posthog-ai/lib/openai/index.mjs` | 2.56 kB |
| `posthog-ai/lib/vercel/index.cjs` | 3.95 kB |
| `posthog-ai/lib/vercel/index.mjs` | 3.9 kB |
| `posthog-react-native/lib/posthog-core/src/eventemitter.js` | 1.08 kB |
| `posthog-react-native/lib/posthog-core/src/featureFlagUtils.js` | 1.51 kB |
| `posthog-react-native/lib/posthog-core/src/lz-string.js` | 1.42 kB |
| `posthog-react-native/lib/posthog-core/src/types.js` | 1.07 kB |
| `posthog-react-native/lib/posthog-core/src/utils.js` | 1.84 kB |
| `posthog-react-native/lib/posthog-core/src/vendor/uuidv7.js` | 2.04 kB |
| `posthog-react-native/lib/posthog-react-native/index.js` | 477 B |
| `posthog-react-native/lib/posthog-react-native/src/autocapture.js` | 1.8 kB |
| `posthog-react-native/lib/posthog-react-native/src/frameworks/wix-navigation.js` | 505 B |
| `posthog-react-native/lib/posthog-react-native/src/hooks/useFeatureFlag.js` | 437 B |
| `posthog-react-native/lib/posthog-react-native/src/hooks/useFeatureFlags.js` | 362 B |
| `posthog-react-native/lib/posthog-react-native/src/hooks/useNavigationTracker.js` | 707 B |
| `posthog-react-native/lib/posthog-react-native/src/hooks/usePostHog.js` | 249 B |
| `posthog-react-native/lib/posthog-react-native/src/legacy.js` | 810 B |
| `posthog-react-native/lib/posthog-react-native/src/native-deps.js` | 1.34 kB |
| `posthog-react-native/lib/posthog-react-native/src/optional/OptionalAsyncStorage.js` | 183 B |
| `posthog-react-native/lib/posthog-react-native/src/optional/OptionalExpoApplication.js` | 215 B |
| `posthog-react-native/lib/posthog-react-native/src/optional/OptionalExpoDevice.js` | 211 B |
| `posthog-react-native/lib/posthog-react-native/src/optional/OptionalExpoFileSystem.js` | 224 B |
| `posthog-react-native/lib/posthog-react-native/src/optional/OptionalExpoLocalization.js` | 216 B |
| `posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeDeviceInfo.js` | 220 B |
| `posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeLocalize.js` | 169 B |
| `posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeNavigation.js` | 218 B |
| `posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeNavigationWix.js` | 222 B |
| `posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeSafeArea.js` | 312 B |
| `posthog-react-native/lib/posthog-react-native/src/optional/OptionalSessionReplay.js` | 231 B |
| `posthog-react-native/lib/posthog-react-native/src/posthog-rn.js` | 4.93 kB |
| `posthog-react-native/lib/posthog-react-native/src/PostHogContext.js` | 210 B |
| `posthog-react-native/lib/posthog-react-native/src/PostHogProvider.js` | 1.75 kB |
| `posthog-react-native/lib/posthog-react-native/src/storage.js` | 1.09 kB |
| `posthog-react-native/lib/posthog-react-native/src/surveys/components/BottomSection.js` | 630 B |
| `posthog-react-native/lib/posthog-react-native/src/surveys/components/Cancel.js` | 527 B |
| `posthog-react-native/lib/posthog-react-native/src/surveys/components/ConfirmationMessage.js` | 738 B |
| `posthog-react-native/lib/posthog-react-native/src/surveys/components/QuestionHeader.js` | 541 B |
| `posthog-react-native/lib/posthog-react-native/src/surveys/components/QuestionTypes.js` | 2.81 kB |
| `posthog-react-native/lib/posthog-react-native/src/surveys/components/Surveys.js` | 1.82 kB |
| `posthog-react-native/lib/posthog-react-native/src/surveys/getActiveMatchingSurveys.js` | 902 B |
| `posthog-react-native/lib/posthog-react-native/src/surveys/icons.js` | 1.86 kB |
| `posthog-react-native/lib/posthog-react-native/src/surveys/index.js` | 222 B |
| `posthog-react-native/lib/posthog-react-native/src/surveys/PostHogSurveyProvider.js` | 1.82 kB |
| `posthog-react-native/lib/posthog-react-native/src/surveys/surveys-utils.js` | 2.33 kB |
| `posthog-react-native/lib/posthog-react-native/src/surveys/useActivatedSurveys.js` | 1.41 kB |
| `posthog-react-native/lib/posthog-react-native/src/surveys/useSurveyStorage.js` | 690 B |
| `posthog-react-native/lib/posthog-react-native/src/types.js` | 90 B |
| `posthog-react-native/lib/posthog-react-native/src/version.js` | 124 B |

</details>



<a href="https://github.com/preactjs/compressed-size-action"><sub>compressed-size-action</sub></a>
author_association: NONE
user: login: marandaneto
created_at: 2025-05-07T09:59:14Z
body: > Yeah, Pressable fix makes sense. Will modal content be rendered on top now though as expected? Any effect on keyboard avoidance? (on mobile now can't test) 

All the same
author_association: MEMBER