Skip to content

feat(surveys): add validation types and utilities#2820

Merged
ordehi merged 17 commits intomainfrom
feat/survey-validation
Feb 9, 2026
Merged

feat(surveys): add validation types and utilities#2820
ordehi merged 17 commits intomainfrom
feat/survey-validation

Conversation

@ordehi
Copy link
Copy Markdown
Contributor

@ordehi ordehi commented Dec 29, 2025

Problem

Relies on PostHog/posthog#44076 for setting lengths in surveys, but works without it as it's back compat.

Survey open text questions with optional: false (required) currently accept whitespace-only responses like " " as valid input. Users can bypass required field validation by entering just spaces. Additionally, there's no way to configure validation rules (like minimum length) for survey responses.

Changes

CleanShot 2025-12-29 at 18 28 20

React Native:

CleanShot 2025-12-29 at 19 18 50

  • Core (@posthog/core): Added SurveyValidationType enum and SurveyValidationRule interface. Created getValidationError(), getMinLengthFromRules(), and getMaxLengthFromRules() utilities in new surveys/validation.ts module. Extended SurveyQuestionBase type with optional validation field.
  • Browser SDK (posthog-js): Updated OpenTextQuestion component to use validation utilities. Now trims responses before submission, uses HTML5 setCustomValidity() for native validation UI, and supports minLength/maxLength textarea attributes. Added Playwright E2E tests.
  • React Native SDK (posthog-react-native): Updated OpenTextQuestion component with validation error state, red border on error, error text display below input, and trim on submit. Added unit tests.

Backwards compatible: Existing surveys without validation rules work unchanged but now properly reject blank responses. API surveys receive validation rules in data but enforcement is left to the user (they can import getValidationError from @posthog/core).

Libraries affected

  • All of them
  • posthog-js (web)
  • posthog-js-lite (web lite)
  • posthog-node
  • posthog-react-native
  • @posthog/react
  • @posthog/ai
  • @posthog/nextjs-config
  • @posthog/nuxt
  • @posthog/rollup-plugin
  • @posthog/webpack-plugin

Checklist

  • Tests for new code
  • Accounted for the impact of any changes across different platforms
  • Accounted for backwards compatibility of any changes (no breaking changes!)
  • Took care not to unnecessarily increase the bundle size

If releasing new changes

  • Ran pnpm changeset to generate a changeset file
  • Added the "release" label to the PR to indicate we're publishing new versions for the affected packages

Joshua Ordehi added 4 commits December 29, 2025 11:52
- Add SurveyValidationType enum (MinLength, MaxLength, Email)
- Add SurveyValidationRule interface
- Add validation field to SurveyQuestionBase type
- Create validation utility functions:
  - getValidationError() - validates survey responses with trim fix
  - getMinLengthFromRules() - extract minLength from rules
  - getMaxLengthFromRules() - extract maxLength from rules
- Add comprehensive unit tests with 100% coverage
- Backwards compatible with existing surveys
- Import validation utilities from @posthog/core
- Update OpenTextQuestion with validation-aware implementation:
  - Use useMemo for validation error calculation
  - Native HTML5 setCustomValidity for error display
  - Add minLength/maxLength textarea attributes
  - Trim response on submit
- Add validation field to browser SurveyQuestionBase type
- Add Playwright E2E tests for validation scenarios
…stion

- Import getValidationError from @posthog/core
- Update OpenTextQuestion with validation-aware implementation:
  - Add validationError state
  - Show error text below input when validation fails
  - Red border on input when error present
  - Disable submit when validation fails
  - Trim response on submit
- Add validationError style to StyleSheet
- Add unit tests for validation in React Native
@ordehi ordehi added the release label Dec 29, 2025
@vercel
Copy link
Copy Markdown

vercel Bot commented Dec 29, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
posthog-js Ready Ready Preview Feb 9, 2026 5:44pm
posthog-nextjs-config Ready Ready Preview Feb 9, 2026 5:44pm

Request Review

Comment thread packages/core/src/surveys/validation.ts Fixed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Dec 29, 2025

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Dec 29, 2025

Size Change: +15.7 kB (+0.27%)

Total Size: 5.92 MB

Filename Size Change
packages/browser/dist/all-external-dependencies.js 268 kB +1.13 kB (+0.42%)
packages/browser/dist/array.full.es5.js 319 kB +1.11 kB (+0.35%)
packages/browser/dist/array.full.js 420 kB +1.04 kB (+0.25%)
packages/browser/dist/array.full.no-external.js 439 kB +1.04 kB (+0.24%)
packages/browser/dist/array.js 175 kB -89 B (-0.05%)
packages/browser/dist/array.no-external.js 189 kB -89 B (-0.05%)
packages/browser/dist/main.js 176 kB -89 B (-0.05%)
packages/browser/dist/module.full.js 420 kB +1.04 kB (+0.25%)
packages/browser/dist/module.full.no-external.js 440 kB +1.04 kB (+0.24%)
packages/browser/dist/module.js 176 kB -89 B (-0.05%)
packages/browser/dist/module.no-external.js 190 kB -89 B (-0.05%)
packages/browser/dist/surveys-preview.js 76.3 kB +1.13 kB (+1.51%)
packages/browser/dist/surveys.js 90 kB +1.13 kB (+1.27%)
packages/core/dist/index.js 6.87 kB +1.18 kB (+20.65%) 🚨
packages/core/dist/index.mjs 650 B +165 B (+34.02%) 🚨
packages/core/dist/types.js 9.5 kB +375 B (+4.11%)
packages/core/dist/types.mjs 6.95 kB +280 B (+4.2%)
packages/react-native/dist/surveys/components/QuestionTypes.js 12.7 kB +898 B (+7.58%) 🔍
packages/core/dist/surveys/validation.js 3.06 kB +3.06 kB (new file) 🆕
packages/core/dist/surveys/validation.mjs 1.51 kB +1.51 kB (new file) 🆕
ℹ️ View Unchanged
Filename Size Change
packages/ai/dist/anthropic/index.cjs 19.6 kB 0 B
packages/ai/dist/anthropic/index.mjs 19.2 kB 0 B
packages/ai/dist/gemini/index.cjs 26.2 kB 0 B
packages/ai/dist/gemini/index.mjs 26 kB 0 B
packages/ai/dist/index.cjs 160 kB 0 B
packages/ai/dist/index.mjs 159 kB 0 B
packages/ai/dist/langchain/index.cjs 45.3 kB 0 B
packages/ai/dist/langchain/index.mjs 44.8 kB 0 B
packages/ai/dist/openai/index.cjs 46 kB 0 B
packages/ai/dist/openai/index.mjs 45.7 kB 0 B
packages/ai/dist/vercel/index.cjs 34.7 kB 0 B
packages/ai/dist/vercel/index.mjs 34.7 kB 0 B
packages/browser/dist/conversations.js 46.2 kB 0 B
packages/browser/dist/crisp-chat-integration.js 2.11 kB 0 B
packages/browser/dist/customizations.full.js 18 kB 0 B
packages/browser/dist/dead-clicks-autocapture.js 13.1 kB 0 B
packages/browser/dist/element-inference.js 5.85 kB 0 B
packages/browser/dist/exception-autocapture.js 11.9 kB 0 B
packages/browser/dist/external-scripts-loader.js 3.04 kB 0 B
packages/browser/dist/intercom-integration.js 2.16 kB 0 B
packages/browser/dist/lazy-recorder.js 152 kB 0 B
packages/browser/dist/logs.js 38.8 kB 0 B
packages/browser/dist/posthog-recorder.js 251 kB 0 B
packages/browser/dist/product-tours-preview.js 75.9 kB 0 B
packages/browser/dist/product-tours.js 112 kB 0 B
packages/browser/dist/recorder-v2.js 113 kB 0 B
packages/browser/dist/recorder.js 113 kB 0 B
packages/browser/dist/tracing-headers.js 1.93 kB 0 B
packages/browser/dist/web-vitals-with-attribution.js 12 kB 0 B
packages/browser/dist/web-vitals.js 6.6 kB 0 B
packages/browser/react/dist/esm/index.js 19.3 kB 0 B
packages/browser/react/dist/esm/surveys/index.js 2.2 kB 0 B
packages/browser/react/dist/umd/index.js 22.4 kB 0 B
packages/browser/react/dist/umd/surveys/index.js 2.98 kB 0 B
packages/core/dist/error-tracking/chunk-ids.js 2.54 kB 0 B
packages/core/dist/error-tracking/chunk-ids.mjs 1.31 kB 0 B
packages/core/dist/error-tracking/coercers/dom-exception-coercer.js 2.3 kB 0 B
packages/core/dist/error-tracking/coercers/dom-exception-coercer.mjs 993 B 0 B
packages/core/dist/error-tracking/coercers/error-coercer.js 2.02 kB 0 B
packages/core/dist/error-tracking/coercers/error-coercer.mjs 794 B 0 B
packages/core/dist/error-tracking/coercers/error-event-coercer.js 1.76 kB 0 B
packages/core/dist/error-tracking/coercers/error-event-coercer.mjs 513 B 0 B
packages/core/dist/error-tracking/coercers/event-coercer.js 1.82 kB 0 B
packages/core/dist/error-tracking/coercers/event-coercer.mjs 548 B 0 B
packages/core/dist/error-tracking/coercers/index.js 6.79 kB 0 B
packages/core/dist/error-tracking/coercers/index.mjs 326 B 0 B
packages/core/dist/error-tracking/coercers/object-coercer.js 3.46 kB 0 B
packages/core/dist/error-tracking/coercers/object-coercer.mjs 2.07 kB 0 B
packages/core/dist/error-tracking/coercers/primitive-coercer.js 1.67 kB 0 B
packages/core/dist/error-tracking/coercers/primitive-coercer.mjs 419 B 0 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.js 2.25 kB 0 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.mjs 904 B 0 B
packages/core/dist/error-tracking/coercers/string-coercer.js 2.01 kB 0 B
packages/core/dist/error-tracking/coercers/string-coercer.mjs 820 B 0 B
packages/core/dist/error-tracking/coercers/utils.js 2.06 kB 0 B
packages/core/dist/error-tracking/coercers/utils.mjs 716 B 0 B
packages/core/dist/error-tracking/error-properties-builder.js 5.56 kB 0 B
packages/core/dist/error-tracking/error-properties-builder.mjs 4.23 kB 0 B
packages/core/dist/error-tracking/index.js 4.11 kB 0 B
packages/core/dist/error-tracking/index.mjs 152 B 0 B
packages/core/dist/error-tracking/parsers/base.js 1.83 kB 0 B
packages/core/dist/error-tracking/parsers/base.mjs 464 B 0 B
packages/core/dist/error-tracking/parsers/chrome.js 2.73 kB 0 B
packages/core/dist/error-tracking/parsers/chrome.mjs 1.32 kB 0 B
packages/core/dist/error-tracking/parsers/gecko.js 2.47 kB 0 B
packages/core/dist/error-tracking/parsers/gecko.mjs 1.13 kB 0 B
packages/core/dist/error-tracking/parsers/index.js 4.75 kB 0 B
packages/core/dist/error-tracking/parsers/index.mjs 2.1 kB 0 B
packages/core/dist/error-tracking/parsers/node.js 3.94 kB 0 B
packages/core/dist/error-tracking/parsers/node.mjs 2.68 kB 0 B
packages/core/dist/error-tracking/parsers/opera.js 2.26 kB 0 B
packages/core/dist/error-tracking/parsers/opera.mjs 746 B 0 B
packages/core/dist/error-tracking/parsers/safari.js 1.88 kB 0 B
packages/core/dist/error-tracking/parsers/safari.mjs 574 B 0 B
packages/core/dist/error-tracking/parsers/winjs.js 1.72 kB 0 B
packages/core/dist/error-tracking/parsers/winjs.mjs 426 B 0 B
packages/core/dist/error-tracking/types.js 1.33 kB 0 B
packages/core/dist/error-tracking/types.mjs 131 B 0 B
packages/core/dist/error-tracking/utils.js 1.8 kB 0 B
packages/core/dist/error-tracking/utils.mjs 604 B 0 B
packages/core/dist/eventemitter.js 1.78 kB 0 B
packages/core/dist/eventemitter.mjs 571 B 0 B
packages/core/dist/featureFlagUtils.js 6.5 kB 0 B
packages/core/dist/featureFlagUtils.mjs 4.28 kB 0 B
packages/core/dist/gzip.js 1.88 kB 0 B
packages/core/dist/gzip.mjs 577 B 0 B
packages/core/dist/posthog-core-stateless.js 31.1 kB 0 B
packages/core/dist/posthog-core-stateless.mjs 28.6 kB 0 B
packages/core/dist/posthog-core.js 38.1 kB 0 B
packages/core/dist/posthog-core.mjs 33.2 kB 0 B
packages/core/dist/process/index.js 2.77 kB 0 B
packages/core/dist/process/index.mjs 114 B 0 B
packages/core/dist/process/spawn-local.js 1.82 kB 0 B
packages/core/dist/process/spawn-local.mjs 568 B 0 B
packages/core/dist/process/utils.js 3.27 kB 0 B
packages/core/dist/process/utils.mjs 1.3 kB 0 B
packages/core/dist/testing/index.js 2.93 kB 0 B
packages/core/dist/testing/index.mjs 79 B 0 B
packages/core/dist/testing/PostHogCoreTestClient.js 3.15 kB 0 B
packages/core/dist/testing/PostHogCoreTestClient.mjs 1.74 kB 0 B
packages/core/dist/testing/test-utils.js 2.77 kB 0 B
packages/core/dist/testing/test-utils.mjs 1.09 kB 0 B
packages/core/dist/utils/bot-detection.js 3.28 kB 0 B
packages/core/dist/utils/bot-detection.mjs 1.95 kB 0 B
packages/core/dist/utils/bucketed-rate-limiter.js 3 kB 0 B
packages/core/dist/utils/bucketed-rate-limiter.mjs 1.62 kB 0 B
packages/core/dist/utils/index.js 11.9 kB 0 B
packages/core/dist/utils/index.mjs 1.98 kB 0 B
packages/core/dist/utils/logger.js 2.5 kB 0 B
packages/core/dist/utils/logger.mjs 1.22 kB 0 B
packages/core/dist/utils/number-utils.js 2 kB 0 B
packages/core/dist/utils/number-utils.mjs 735 B 0 B
packages/core/dist/utils/promise-queue.js 2 kB 0 B
packages/core/dist/utils/promise-queue.mjs 768 B 0 B
packages/core/dist/utils/string-utils.js 2.73 kB 0 B
packages/core/dist/utils/string-utils.mjs 1.09 kB 0 B
packages/core/dist/utils/type-utils.js 7.03 kB 0 B
packages/core/dist/utils/type-utils.mjs 3.1 kB 0 B
packages/core/dist/utils/user-agent-utils.js 14.9 kB 0 B
packages/core/dist/utils/user-agent-utils.mjs 11.9 kB 0 B
packages/core/dist/vendor/uuidv7.js 8.29 kB 0 B
packages/core/dist/vendor/uuidv7.mjs 6.72 kB 0 B
packages/nextjs-config/dist/config.js 4.97 kB 0 B
packages/nextjs-config/dist/config.mjs 3.48 kB 0 B
packages/nextjs-config/dist/index.js 2.24 kB 0 B
packages/nextjs-config/dist/index.mjs 30 B 0 B
packages/nextjs-config/dist/utils.js 3.96 kB 0 B
packages/nextjs-config/dist/utils.mjs 1.85 kB 0 B
packages/node/dist/client.js 30 kB 0 B
packages/node/dist/client.mjs 28 kB 0 B
packages/node/dist/entrypoints/index.edge.js 4.25 kB 0 B
packages/node/dist/entrypoints/index.edge.mjs 723 B 0 B
packages/node/dist/entrypoints/index.node.js 5.55 kB 0 B
packages/node/dist/entrypoints/index.node.mjs 1.08 kB 0 B
packages/node/dist/experimental.js 603 B 0 B
packages/node/dist/experimental.mjs 0 B 0 B 🆕
packages/node/dist/exports.js 4.22 kB 0 B
packages/node/dist/exports.mjs 203 B 0 B
packages/node/dist/extensions/context/context.js 2.12 kB 0 B
packages/node/dist/extensions/context/context.mjs 862 B 0 B
packages/node/dist/extensions/context/types.js 603 B 0 B
packages/node/dist/extensions/context/types.mjs 0 B 0 B 🆕
packages/node/dist/extensions/error-tracking/autocapture.js 2.66 kB 0 B
packages/node/dist/extensions/error-tracking/autocapture.mjs 1.24 kB 0 B
packages/node/dist/extensions/error-tracking/index.js 4.2 kB 0 B
packages/node/dist/extensions/error-tracking/index.mjs 2.91 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.js 8.81 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.mjs 7.15 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/module.node.js 2.78 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/module.node.mjs 1.45 kB 0 B
packages/node/dist/extensions/express.js 2.84 kB 0 B
packages/node/dist/extensions/express.mjs 1.25 kB 0 B
packages/node/dist/extensions/feature-flags/cache.js 603 B 0 B
packages/node/dist/extensions/feature-flags/cache.mjs 0 B 0 B 🆕
packages/node/dist/extensions/feature-flags/crypto.js 1.57 kB 0 B
packages/node/dist/extensions/feature-flags/crypto.mjs 395 B 0 B
packages/node/dist/extensions/feature-flags/feature-flags.js 32.2 kB 0 B
packages/node/dist/extensions/feature-flags/feature-flags.mjs 30.2 kB 0 B
packages/node/dist/extensions/sentry-integration.js 4.66 kB 0 B
packages/node/dist/extensions/sentry-integration.mjs 3.17 kB 0 B
packages/node/dist/storage-memory.js 1.52 kB 0 B
packages/node/dist/storage-memory.mjs 297 B 0 B
packages/node/dist/types.js 1.43 kB 0 B
packages/node/dist/types.mjs 224 B 0 B
packages/node/dist/version.js 1.21 kB 0 B
packages/node/dist/version.mjs 47 B 0 B
packages/nuxt/dist/module.mjs 4.39 kB 0 B
packages/nuxt/dist/runtime/composables/useFeatureFlagEnabled.js 566 B 0 B
packages/nuxt/dist/runtime/composables/useFeatureFlagPayload.js 597 B 0 B
packages/nuxt/dist/runtime/composables/useFeatureFlagVariantKey.js 591 B 0 B
packages/nuxt/dist/runtime/composables/usePostHog.js 128 B 0 B
packages/nuxt/dist/runtime/nitro-plugin.js 1.08 kB 0 B
packages/nuxt/dist/runtime/vue-plugin.js 1.14 kB 0 B
packages/react-native/dist/autocapture.js 5.05 kB 0 B
packages/react-native/dist/error-tracking/index.js 6.77 kB 0 B
packages/react-native/dist/error-tracking/utils.js 2.58 kB 0 B
packages/react-native/dist/frameworks/wix-navigation.js 1.3 kB 0 B
packages/react-native/dist/hooks/useFeatureFlag.js 1.49 kB 0 B
packages/react-native/dist/hooks/useFeatureFlags.js 821 B 0 B
packages/react-native/dist/hooks/useNavigationTracker.js 2.46 kB 0 B
packages/react-native/dist/hooks/usePostHog.js 467 B 0 B
packages/react-native/dist/index.js 3.12 kB 0 B
packages/react-native/dist/native-deps.js 8.16 kB 0 B
packages/react-native/dist/optional/OptionalAsyncStorage.js 299 B 0 B
packages/react-native/dist/optional/OptionalExpoApplication.js 377 B 0 B
packages/react-native/dist/optional/OptionalExpoDevice.js 347 B 0 B
packages/react-native/dist/optional/OptionalExpoFileSystem.js 386 B 0 B
packages/react-native/dist/optional/OptionalExpoFileSystemLegacy.js 423 B 0 B
packages/react-native/dist/optional/OptionalExpoLocalization.js 383 B 0 B
packages/react-native/dist/optional/OptionalReactNativeDeviceInfo.js 415 B 0 B
packages/react-native/dist/optional/OptionalReactNativeLocalize.js 303 B 0 B
packages/react-native/dist/optional/OptionalReactNativeNavigation.js 415 B 0 B
packages/react-native/dist/optional/OptionalReactNativeNavigationWix.js 443 B 0 B
packages/react-native/dist/optional/OptionalReactNativeSafeArea.js 644 B 0 B
packages/react-native/dist/optional/OptionalSessionReplay.js 455 B 0 B
packages/react-native/dist/posthog-rn.js 31.3 kB 0 B
packages/react-native/dist/PostHogContext.js 329 B 0 B
packages/react-native/dist/PostHogMaskView.js 1.66 kB 0 B
packages/react-native/dist/PostHogProvider.js 4.77 kB 0 B
packages/react-native/dist/storage.js 4.49 kB 0 B
packages/react-native/dist/surveys/components/BottomSection.js 1.46 kB 0 B
packages/react-native/dist/surveys/components/Cancel.js 909 B 0 B
packages/react-native/dist/surveys/components/ConfirmationMessage.js 1.65 kB 0 B
packages/react-native/dist/surveys/components/QuestionHeader.js 1.37 kB 0 B
packages/react-native/dist/surveys/components/SurveyModal.js 4.01 kB 0 B
packages/react-native/dist/surveys/components/Surveys.js 7.22 kB 0 B
packages/react-native/dist/surveys/getActiveMatchingSurveys.js 2.64 kB 0 B
packages/react-native/dist/surveys/icons.js 8.86 kB 0 B
packages/react-native/dist/surveys/index.js 600 B 0 B
packages/react-native/dist/surveys/PostHogSurveyProvider.js 5.71 kB 0 B
packages/react-native/dist/surveys/surveys-utils.js 12.7 kB 0 B
packages/react-native/dist/surveys/useActivatedSurveys.js 3.67 kB 0 B
packages/react-native/dist/surveys/useSurveyStorage.js 2.16 kB 0 B
packages/react-native/dist/tooling/expoconfig.js 2.63 kB 0 B
packages/react-native/dist/tooling/metroconfig.js 2.32 kB 0 B
packages/react-native/dist/tooling/posthogMetroSerializer.js 4.86 kB 0 B
packages/react-native/dist/tooling/utils.js 4.05 kB 0 B
packages/react-native/dist/tooling/vendor/expo/expoconfig.js 70 B 0 B
packages/react-native/dist/tooling/vendor/metro/countLines.js 237 B 0 B
packages/react-native/dist/tooling/vendor/metro/utils.js 3.35 kB 0 B
packages/react-native/dist/types.js 70 B 0 B
packages/react-native/dist/utils.js 719 B 0 B
packages/react-native/dist/version.js 130 B 0 B
packages/react/dist/esm/index.js 19.3 kB 0 B
packages/react/dist/esm/surveys/index.js 2.2 kB 0 B
packages/react/dist/umd/index.js 22.4 kB 0 B
packages/react/dist/umd/surveys/index.js 2.98 kB 0 B
packages/rollup-plugin/dist/index.js 4.66 kB 0 B
packages/types/dist/capture.js 603 B 0 B
packages/types/dist/capture.mjs 0 B 0 B 🆕
packages/types/dist/common.js 603 B 0 B
packages/types/dist/common.mjs 0 B 0 B 🆕
packages/types/dist/feature-flags.js 603 B 0 B
packages/types/dist/feature-flags.mjs 0 B 0 B 🆕
packages/types/dist/index.js 603 B 0 B
packages/types/dist/index.mjs 0 B 0 B 🆕
packages/types/dist/posthog-config.js 603 B 0 B
packages/types/dist/posthog-config.mjs 0 B 0 B 🆕
packages/types/dist/posthog.js 603 B 0 B
packages/types/dist/posthog.mjs 0 B 0 B 🆕
packages/types/dist/request.js 603 B 0 B
packages/types/dist/request.mjs 0 B 0 B 🆕
packages/types/dist/segment.js 603 B 0 B
packages/types/dist/segment.mjs 0 B 0 B 🆕
packages/types/dist/session-recording.js 603 B 0 B
packages/types/dist/session-recording.mjs 0 B 0 B 🆕
packages/types/dist/survey.js 603 B 0 B
packages/types/dist/survey.mjs 0 B 0 B 🆕
packages/types/dist/toolbar.js 603 B 0 B
packages/types/dist/toolbar.mjs 0 B 0 B 🆕
packages/web/dist/index.cjs 13.8 kB 0 B
packages/web/dist/index.mjs 13.7 kB 0 B
packages/webpack-plugin/dist/config.js 2.69 kB 0 B
packages/webpack-plugin/dist/config.mjs 1.69 kB 0 B
packages/webpack-plugin/dist/index.js 6.47 kB 0 B
packages/webpack-plugin/dist/index.mjs 3.05 kB 0 B
tooling/changelog/dist/index.js 3.31 kB 0 B
tooling/rollup-utils/dist/index.js 1.17 kB 0 B

compressed-size-action

Fixes CodeQL security alert about polynomial regex vulnerability.
The previous email regex pattern could cause exponential backtracking
on malicious inputs like '!@!.!.!.!.!.'.

Changes:
- Replace regex with simple string-based isValidEmail() function
- Add tests for edge cases (multiple @, dots at boundaries, ReDoS)
- Fix survey preview test to use fireEvent.input instead of change
Follow established pattern in other Playwright tests where route promise
is stored and awaited after start() to ensure proper test setup.
- Await route setup promise after start() per established pattern
- Wait for .survey-form inside container, not just container div
- Check button is disabled for validation failures instead of clicking
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment thread packages/react-native/src/surveys/components/QuestionTypes.tsx Outdated
Use useMemo to calculate validation error once per render instead of
calling getValidationError twice (in submitDisabled and handleSubmit).
…type

Remove email validation from the validation system - email collection
will be implemented as a dedicated question type with:
- Privacy-first masked input
- Proper email input type with native validation
- Option for multiple email collection

Kept minLength and maxLength validators.
@ordehi
Copy link
Copy Markdown
Contributor Author

ordehi commented Dec 29, 2025

Been thinking about this, this PR was conflating too many concerns. The user's original issue was that users can bypass required questions by entering empty spaces, I've kept that fix and the length utilities. However, for emails we should consider adding a specific "Email" question type that uses a proper email field for privacy and full email validation.

Now, users will be able to enforce a minimum and maximum length in text type questions, which is helpful if their getting many useless answers, but if they don't set a length constraint, they'll still get the benefit of not getting empty spaces that by pass required responses.

@ordehi ordehi requested a review from adboio December 29, 2025 23:20
@marandaneto marandaneto requested a review from a team December 30, 2025 12:57
Comment thread packages/browser/src/extensions/surveys/components/QuestionTypes.tsx Outdated
Comment thread packages/core/src/surveys/validation.ts
Comment thread packages/react-native/src/surveys/components/QuestionTypes.tsx Outdated
…logic

- Extract duplicated hint string building to shared util in core
- Skip showing hint for min=1 (redundant for required, useless for optional)
- Add pluralization for edge cases (e.g., "Maximum 1 character")
- Add comprehensive tests for the new util
Copy link
Copy Markdown
Contributor

@lucasheriques lucasheriques left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor comment. PR looks great overall

value: string,
rules: SurveyValidationRule[] | undefined,
optional: boolean | undefined
): string | false {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: i'd remove this return types and use typescript infer instead

@github-actions
Copy link
Copy Markdown
Contributor

This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, post a comment or remove the stale label – otherwise this will be closed in another week.

@github-actions github-actions Bot added the stale label Jan 19, 2026
Copy link
Copy Markdown
Contributor

adboio commented Jan 19, 2026

@ordehi is this good to merge? just checking in!

@github-actions github-actions Bot removed the stale label Jan 20, 2026
Comment on lines +144 to +145
minLength={minLength}
maxLength={maxLength}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical bug: HTML5 minLength and maxLength attributes validate the raw untrimmed value, but the custom validation logic validates the trimmed value (line 113 calls getValidationError which trims on line 12 of validation.ts). This creates inconsistent behavior:

Example scenario with maxLength=10:

  • User types " hello world " (15 chars raw, 11 chars trimmed)
  • HTML5 maxLength prevents typing beyond 10 characters, blocking at " hello wo"
  • User can't type more, but trimmed value is only 8 chars
  • Custom validation may expect more characters if minLength > 8

Fix: Remove these HTML5 attributes since validation is handled by custom logic:

<textarea
    id={htmlFor}
    rows={4}
    placeholder={appearance?.placeholder}
    // Remove minLength and maxLength attributes
    onInput={(e) => {
Suggested change
minLength={minLength}
maxLength={maxLength}

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 2, 2026

This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, post a comment or remove the stale label – otherwise this will be closed in another week.

@github-actions github-actions Bot added stale and removed stale labels Feb 2, 2026
Resolve conflicts:
- QuestionTypes.tsx: Keep validation utilities and add thumbs emoji imports
- posthog-surveys-types.ts: Keep Properties and SurveyValidationRule imports
@ordehi ordehi requested a review from a team as a code owner February 9, 2026 17:37
@ordehi ordehi merged commit d578824 into main Feb 9, 2026
45 checks passed
@ordehi ordehi deleted the feat/survey-validation branch February 9, 2026 18:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants