React Native Flow

← Retour au blog

March 13, 2026·10 min read

Keyboards and forms that don’t fight the user

Nothing says “we didn’t test on a phone” like a keyboard eating the only button that submits the form. A mix of layout, platform tweaks, and sometimes `react-native-keyboard-controller` fixes most cases. Treat keyboard handling as part of the feature, not polish you add after QA finds the bug.

Start with layout

ScrollViews that wrap the whole form beat rigid columns when the keyboard appears. Safe area + keyboard padding together matter on notched phones.

Test with the smallest phone you support, not just the Pro Max in the office.

Platform split is normal

Android’s `adjustResize` vs `adjustPan` changes behavior dramatically. iOS needs different offsets than Android for the same visual result.

Document which mode you rely on in `AndroidManifest` so a merge doesn’t silently revert it.

When to reach for a library

If you’re fighting focus scroll-to-input and multiple fields, a keyboard controller library can pay for itself. Still verify accessibility: screen reader users shouldn’t lose context when the keyboard opens.

Don’t block the dismiss gesture with transparent overlays.

What to test on a real device

Open the screen, focus the first field, advance through the form with “next,” and submit with the keyboard visible. Rotate the device, switch dark mode, and try Android gesture navigation back—half the regressions live in system UI edges.

If you support external keyboards on tablets, verify tab order and that focus rings do not jump off-screen.

Understanding platform keyboard models

iOS and Android move content differently when the keyboard appears. iOS often pairs safe areas with keyboard frame notifications; Android relies on window soft input modes and sometimes needs `android:windowSoftInputMode` tweaks in the manifest. React Native bridges these behaviors but not identically across versions. Do not assume `KeyboardAvoidingView` alone fixes all forms—sometimes a `ScrollView` with `keyboardShouldPersistTaps` and manual padding wins. Tablets and foldables introduce split modes and external keyboards; test them if your audience uses them. Web, if you share code via React Native Web, has yet another model—guard platform-specific branches clearly.

Layout patterns that survive real devices

Full-screen scrollable forms beat rigid columns for long inputs. Pin primary actions in reachable zones; avoid placing submit buttons where keyboard toolbars cover them. For multi-step flows, preserve field values across steps and handle back navigation without losing data. Sticky headers can interfere with keyboard-driven scroll adjustments—prototype early. When using bottom sheets, verify keyboard pushes sheet content correctly or dismisses the sheet intentionally. Z-index and elevation issues often manifest only on certain OEM skins—keep a junk-drawer device for testing.

Libraries versus hand-rolled solutions

`react-native-keyboard-controller` and similar libraries solve focus scrolling and interactive keyboard dismissal with less boilerplate. They add native code and upgrade obligations—evaluate whether your pain justifies the dependency. If you hand-roll, centralize keyboard listeners so you do not duplicate offsets across screens. Whichever path, test with screen readers: accessibility focus should follow inputs logically. Avoid capturing all touches in parent views that block keyboard dismiss gestures—users hate trapped keyboards.

Edge cases: modals, web views, and secure fields

Secure text entry and password managers can alter field focus behavior. WebViews inside forms may steal focus or scroll oddly—consider isolating WebViews on separate screens. OTP auto-fill can jump focus; validate that your state updates keep pace. Multi-window and picture-in-picture modes on tablets may resize your layout unexpectedly. Document these quirks for QA. When using third-party input masks, ensure they do not fight controlled component updates, especially with rapid paste events.

Performance and re-renders while typing

Heavy validation on every keystroke can jank forms. Debounce async validation, move expensive checks to blur events when possible, and avoid cascading setState storms from masked inputs. If you highlight invalid fields, batch style updates. Large dropdowns or suggestion lists under inputs should virtualize or cap results. Memory churn from logging in render functions shows up as keyboard lag on older phones—profile before optimizing blindly.

Testing matrix for keyboard UX

Cover smallest and largest phones, Android gesture navigation, iOS with and without hardware keyboard attached, dark mode, and rotation if supported. Test password manager flows and switching between secure and non-secure fields. Automate what you can in Detox/Maestro with keyboard helpers, but keep manual exploratory passes—some issues only appear with real IMEs. Log crashes tied to `RCTTextInput` or `Keyboard` events for triage.

Shipping checklist

Primary action visible with keyboard open, no covered inputs, sensible scroll-to-focused-field behavior, dismiss on tap outside where expected, accessible labels on fields and errors, error text not clipped, and performance acceptable on a mid-tier Android device. After release, watch support tickets about ‘cannot submit’—often keyboard overlaps. Iterate quickly; keyboard bugs directly hit conversion.

Shipping and reliability habits (1)

Deep links are a cross-team system: marketing URLs, hosted association files, entitlements, router params, and analytics query preservation. Debug with structured logging of raw URLs (scrub secrets) and reproduce cold-start races with auth hydration. Staging and production should be obviously separated—accidentally opening prod from a QA link erodes trust and pollutes data.

Push notifications walk a line between helpful and intrusive. Prime users with context, respect notification channels on Android, and measure opt-outs after campaigns—spikes mean copy or frequency problems. Payload design affects background behavior; test killed and locked-device states. Tokens belong server-side with rotation strategies; never treat the client as authoritative for subscription state.

Platform differences worth rehearsing (2)

Keyboard and form UX separate polished apps from ‘works on desktop simulators.’ Platform differences in soft input modes matter; test smallest phones and Android gesture navigation. Primary actions must remain reachable when the keyboard is visible—scroll containers and keyboard controllers exist because this problem is universal.

Type-safe navigation pays off when routes multiply. Keep param lists near navigators, validate external URLs, and avoid serializing non-JSON-safe values through params. Renaming routes is a cross-cutting change—update analytics, push payloads, and E2E selectors in the same release train.

Security, privacy, and data handling (3)

Hermes versus JSC is not a lifestyle choice—profile your app. Hermes usually wins on startup; some libraries still assume JSC quirks. Engine toggles are not substitutes for fixing quadratic renders in your own code. Upgrade notes matter: Intl support and debugging tooling evolve.

Reanimated and gesture libraries earn their place when profiling proves UI-thread work and your team can maintain native upgrades. Worklets have constraints—read errors carefully. Respect reduced motion and test Android timing differences—identical JS does not guarantee identical feel.

Performance and measurement discipline (4)

Environment variables should be classified: public-by-design, sensitive-with-mitigations, or never-on-device. `EXPO_PUBLIC_` values are extractable—treat them that way. Align env handling across EAS profiles and local dev; fail fast when keys are missing instead of shipping undefined behavior.

Project structure should make ownership obvious: routes as backbone, feature folders for product areas, thin screens, and shared infrastructure that is deliberately named. Refactor in vertical slices with device-tested releases—big-bang rewrites without tests are how teams lose weeks.

Team process and long-term maintenance (5)

Monorepos amplify both leverage and failure modes: duplicate React versions cause mysterious hook errors, and Metro misconfiguration blocks local packages from resolving. Invest in workspace discipline—single React version, documented `watchFolders`, and lint rules preventing packages from importing app navigators accidentally. CI must mirror local installs; ‘works on my laptop’ with different package managers is a time bomb.

Native modules are product decisions disguised as engineering tasks. You inherit Xcode and Gradle upgrades, store review scrutiny, and security obligations. Prefer maintained Expo modules and config plugins before writing JNI or Swift glue from scratch. When you must go native, budget pairing time with platform specialists and write runbooks for on-call—crashes in native code bypass many JS safeguards.

Shipping and reliability habits (6)

E2E tests should protect revenue paths, not every permutation. Stable selectors (`testID`) beat text that marketing rewrites weekly. Flake management is a feature: quarantine, fix root causes, and keep smoke suites green on CI devices. Five reliable tests beat fifty flaky ones that everyone ignores.

OTA updates are powerful and risky: runtime compatibility, rollback plans, and user-visible behavior changes need governance. Channels should map to release maturity—staging versus production—with access controls on publish credentials. Large assets over cellular need care; silent failures erode trust more than a frank ‘update failed, retry’ message.

Platform differences worth rehearsing (7)

Privacy nutrition labels and Play Data Safety forms should reflect actual SDK behavior—inventory dependencies each release and remove dead code. Drift between claims and telemetry is legal and store risk, not just embarrassment. Involve legal early when adding analytics or ads.

Expo SDK upgrades are integration projects: `expo doctor`, aligned community packages, regenerated native projects, and device smoke tests for camera, push, and IAP. Freeze unrelated native refactors during the upgrade window and keep rollback paths hot. Document surprises for the next upgrade while memory is fresh.

Security, privacy, and data handling (8)

ScrollView versus FlatList is a data-volume question. Small static content belongs in ScrollView; long feeds belong in virtualized lists. Nested scrollables need explicit height contracts—redesign beats fighting physics. Document intentional choices so future refactors do not ‘optimize’ blindly.

Metro cache issues masquerade as logic bugs. Establish a documented reset ladder: dev server restart, cache flags, Watchman, derived data, then dependency reinstalls. Compare platforms when only one breaks—native steps diverge. Keep CI caches deterministic with lockfiles and pinned toolchains.

Performance and measurement discipline (9)

Accessibility is compatibility. Labels, focus order, and dynamic type are not polish—they determine whether users can complete tasks at all. Test with VoiceOver and TalkBack on hardware; simulators miss focus bugs. When designs prioritize minimalism, negotiate text alternatives for icon-only controls. Accessibility regressions often follow navigation redesigns—add checklist items to those PRs specifically.

Internationalization is a product feature, not a string swap. Plural rules, RTL layout, and locale-aware formatting change behavior—not just copy length. Pseudolocale helps find clipping early, but real Arabic and German QA catches nuance. Avoid concatenating translated fragments; context matters. Document glossary terms so translators do not invent inconsistent product names.

Team process and long-term maintenance (10)

Storage is not a database. AsyncStorage and MMKV excel at key-value preferences; SQLite or remote APIs belong elsewhere for relational data. Migrations should be incremental, logged, and non-blocking for UI. Secure tokens need secure storage when your model demands it—speed is not a substitute for correctness on auth material.

WebViews are untrusted browsers inside your app. Validate `postMessage` payloads, lock navigation to expected hosts, and prefer system-browser auth flows when OAuth security demands it. Third-party JavaScript can change without your deploy—treat XSS in web as bridge compromise risk. Clear storage on logout and rate-limit message handlers.

Shipping and reliability habits (11)

Security and privacy expectations move faster than roadmaps. Treat analytics, crash, and attribution SDKs as part of your threat model: initialize them deliberately, document data flows, and verify ‘off’ truly stops network calls. Client-side secrets are public secrets—anything shipped in an APK or IPA should be assumed extractable. Pair mobile changes with backend policies so authorization remains consistent across platforms.

Accessibility is compatibility. Labels, focus order, and dynamic type are not polish—they determine whether users can complete tasks at all. Test with VoiceOver and TalkBack on hardware; simulators miss focus bugs. When designs prioritize minimalism, negotiate text alternatives for icon-only controls. Accessibility regressions often follow navigation redesigns—add checklist items to those PRs specifically.

Platform differences worth rehearsing (12)

Error boundaries catch render failures, not native crashes or async mistakes. Pair them with platform crash reporting and structured client logs. Fallback UI should include build identifiers and humane copy—never raw stack traces for end users. Test fallbacks with screen readers; a broken error screen is still broken UX.

Storage is not a database. AsyncStorage and MMKV excel at key-value preferences; SQLite or remote APIs belong elsewhere for relational data. Migrations should be incremental, logged, and non-blocking for UI. Secure tokens need secure storage when your model demands it—speed is not a substitute for correctness on auth material.

Security, privacy, and data handling (13)

Splash screens and launch gates should reflect honest readiness: fonts, theme, session, critical remote config—not every SDK under the sun. Infinite splash is worse than a slightly longer branded hold. Match native and JS background colors to avoid flashes; respect reduced motion for animations.

JWT and session refresh flows need single-flight refresh, clear logout semantics, and secure storage for refresh tokens when appropriate. Parallel 401s should not stampede refresh endpoints. Clock skew and biometrics policies belong in explicit product decisions, not accidental implementation details.

Sponsorisé

Promo rapide