---
name: forms-and-validation
description: Review React Native forms for validation timing, keyboard handling, error focus, and preserved dirty state. Use when building or reviewing login, signup, checkout, settings, or multi-step forms.
version: 1.1.0
platforms: [ ios, android ]
react-native-version: 0.76+
tags: [ react-native, forms, validation, keyboard ]
title: forms-and-validation
canonical_url: https://skilld.dev/gh/neha/rn-developer-skills/forms-and-validation
last_updated: 2026-10-01T00:04:32.000Z
---

> **Skill from skilld.dev.** Follow the instructions below for this session. You do not need to install anything.
>
> If the user asked to install this Skill, run `npx skilld install neha/rn-developer-skills/forms-and-validation`. Install writes the Skill files into the project, so every session loads them.

# Forms and Validation Skill

## Applicability

- **Platforms:** iOS and Android
- **React Native:** 0.76+ (New Architecture interop assumed unless a checklist item says otherwise)

## When to Use

- Building or reviewing a login, signup, checkout, settings, or other multi-field form
- Changing validation, keyboard behaviour, or submit handling
- Reviewing a wizard or multi-step flow that collects user input

## Severity

- **Merge-blocking:** a double submit, or this diff discards dirty input with no prompt.
- **Should-fix:** validation timing, keyboard, and autofill.

## Guidance

### State

This skill owns whether dirty form input survives navigation.

- [ ] Each field has one source of truth; the screen does not mix uncontrolled inputs with a second copy of the same value
- [ ] Dirty values survive leaving the screen and coming back, including when the app is backgrounded mid-edit
- [ ] A submit in flight is not sent again (the button ignores repeat presses). Retrying a failed POST when the network returns is owned by [state-and-data](../state-and-data/SKILL.md)
- [ ] Leaving with unsaved changes asks the user before discarding, when the data would be lost

### Validation

- [ ] Format checks run on blur or submit, not on every keystroke
- [ ] Server checks (taken email, payment decline) run on submit and map to the field they belong to
- [ ] The first invalid field is scrolled into view and focused
- [ ] Errors are text next to the field and are announced. Colour-only state is owned by [accessibility](../accessibility/SKILL.md)
- [ ] The submit control shows a loading state and stays disabled only while the request is in flight, with a visible reason when it cannot be used

**Incorrect:**
```tsx
<TextInput
  value={email}
  onChangeText={(next) => {
    setEmail(next);
    setEmailError(isEmail(next) ? '' : 'Enter a valid email');
  }}
/>
```

**Correct:**
```tsx
<TextInput
  value={email}
  onChangeText={setEmail}
  onBlur={() => setEmailError(isEmail(email) ? '' : 'Enter a valid email')}
  accessibilityLabel="Email"
  keyboardType="email-address"
  autoCapitalize="none"
  textContentType="emailAddress"
/>
```

### Keyboard and platform input

- [ ] The focused field stays visible above the keyboard (keyboard avoiding view, or a scroll view that knows the keyboard inset)
- [ ] The keyboard type matches the field (email, phone, number, decimal)
- [ ] Secure fields use secure entry and do not log their values
- [ ] Autofill hints (`textContentType` / `autoComplete`) are set for credentials and contact fields
- [ ] A multi-step form keeps earlier steps' values until the whole flow finishes or the user cancels

### Accessibility

- [ ] Every input has a label
- [ ] The error is associated with its field and announced when it appears
- [ ] Focus moves to the error, or the error summary, after a failed submit

## Anti-Patterns

| Anti-Pattern | Risk | Fix |
|---|---|---|
| Validating on every keystroke | The field is "wrong" before the user finishes typing | Validate on blur and on submit |
| Clearing the form when the screen blurs | Back navigation or a permission prompt wipes the draft | Keep draft state above the screen, or in a store that survives the pop |
| Disabling submit with no message | The user cannot tell what is missing | Keep submit available and show field errors, or explain the disabled state |
| Retrying a failed POST automatically | A payment or signup can be created twice | Retry only when the user asks, after confirming the server did not apply it |

## Pitfalls

- iOS and Android report keyboard height differently, and Android's `adjustResize` can double-shift a view that also uses a keyboard-avoiding wrapper. Test both.
- Numeric keyboards still allow paste of non-numeric text. Validate the value, not the keyboard.
- `secureTextEntry` can reset the cursor or clear the field on some Android versions when toggled. Test the show/hide password control.
- A wizard that stores steps only in screen state loses them when a step unmounts. Keep the draft in one place that outlives each step.
