Course outline

React Native / Native descriptions and local interaction / Lesson 5

Text input, drafts, and validation

Keep editable text separate from accepted commands and preserve the draft through a recoverable failure.

About 4 min readContent reviewed
On this page

Lesson goals

  • A controlled input contains an editing draft
  • Parse one explicit boundary contract
  • Commit only after validation succeeds

A controlled input contains an editing draft

TextInput can receive a value string and report edits through onChangeText. The string is a draft, not an already valid domain quantity. Users need intermediate states such as an empty required number while correcting it. Keep that draft separate from the saved record and decide what Save and Cancel mean before wiring remote work. A numeric keyboard is an input hint, not a validator: paste, hardware keyboards, and programmatic values can still supply unexpected text. Persistent labels and recoverable error messages help users understand the rule without relying on a placeholder that disappears.

Parse one explicit boundary contract

The first program accepts ASCII decimal digits after permitted surrounding whitespace is trimmed. It then checks safe integer representation and an illustrative range of1 through20 seats. The range is a synthetic product rule, not a universal reservation limit. Distinguish local format failure from a remote capacity or permission failure. A more detailed parser could return different categories for missing, malformed, and out-of-range input; the example intentionally combines them into one stable error code. Localized user messages should map from that code near presentation rather than matching the literal field label.

javascript Standalone JavaScript model with synthetic local inputs.
function parseSeats(raw) {
  const text = typeof raw === 'string' ? raw.trim() : '';
  if (!/^[0-9]+$/.test(text)) return {ok: false, error: 'INVALID_SEATS'};
  const value = Number(text);
  return Number.isSafeInteger(value) && value >= 1 && value <= 20
    ? {ok: true, value} : {ok: false, error: 'INVALID_SEATS'};
}
console.log(JSON.stringify(parseSeats(' 04 ')));
console.log(JSON.stringify(parseSeats('21')));
console.log(JSON.stringify(parseSeats('4x')));
Expected output
{"ok":true,"value":4}
{"ok":false,"error":"INVALID_SEATS"}
{"ok":false,"error":"INVALID_SEATS"}

The accepted command value is numeric4 while the editing representation can remain04. Invalid text never becomes a fabricated numeric fallback.

Commit only after validation succeeds

The second module receives the parser as an explicit dependency and keeps draft, message, and accepted preview separate. Invalid activation changes the message but preserves the previous accepted preview. The button creates a local preview only; it performs no network save. In a real form, pending state must prevent or otherwise define duplicate activation, and a failed remote save should normally retain useful draft text. Do not mutate a shared saved model on every keystroke if Cancel is supposed to discard edits. The parser dependency must be supplied by the application host.

jsx Illustrative React Native module; requires the declared compatible application host.
import {useState} from 'react';
import {View, Text, TextInput, Button} from 'react-native';
export default function SeatForm({parseSeats}) {
  const [draft, setDraft] = useState('');
  const [accepted, setAccepted] = useState(null);
  const [message, setMessage] = useState('');
  function preview() {
    const result = parseSeats(draft);
    if (!result.ok) { setMessage('Enter 1 through 20 seats'); return; }
    setAccepted(result.value);
    setMessage('Preview ready');
  }
  return <View>
    <Text>Seats</Text>
    <TextInput accessibilityLabel="Seats" value={draft}
      onChangeText={setDraft} keyboardType="number-pad" />
    <Button title="Preview" onPress={preview} />
    <Text>{message}</Text>
    {accepted !== null ? <Text>Seats: {accepted}</Text> : null}
  </View>;
}
Expected output
A valid04 draft predicts Preview ready and Seats: 4; invalid input predicts the range message.

The supplied parser follows the preceding model contract. No keyboard, component renderer, or native form was executed.

Design correction and keyboard behavior together

A field error should identify what can be corrected and remain associated with the relevant input. Choose submit actions and focus movement according to the supported keyboard and target, while keeping a visible submission control. KeyboardAvoidingView behavior and scroll composition require platform-specific review; adding it blindly does not prove the primary action remains reachable. A password or other sensitive field has different normalization and storage rules from a public display label. Do not trim or transform secrets merely because the seat parser trims permitted whitespace. Preserve editing semantics and validate at the accepted-command boundary.

Test local rules separately from remote outcomes

Exercise empty text, zero, both range endpoints, a value just above the limit, leading zeros, and malformed pasted input. Verify correction updates the message without destroying the draft. A valid local count can still be rejected by an authoritative service after availability or authorization changes. Map that outcome distinctly and reconcile uncertain writes instead of retrying blindly. A pure Node parser test cannot establish focus, keyboard avoidance, screen-reader announcements, or server validation. Record those as separate target checks; this course executes no native form and contacts no reservation service.

Common errors and fixes

A number-pad value is assumed valid

Why it happens
The keyboard hint replaced parsing and range validation.
How to fix it
Validate the submitted draft through an explicit parser.
Prevent it next time
Include pasted malformed text and unsafe integers.

Cancel cannot undo edits to saved data

Why it happens
The input updated the authoritative model directly.
How to fix it
Edit a separate draft and commit through a deliberate save command.
Prevent it next time
Specify cancellation before choosing state ownership.

A failed save clears useful text

Why it happens
The draft was reset before confirmed success.
How to fix it
Preserve it until success or explicit user cancellation.
Prevent it next time
Test rejected and uncertain save results.

Check your understanding

1. Why is keeping04 as draft while accepting numeric4 useful?

Show worked solution

Editing representation and domain value serve different purposes. The user can correct the text without every keystroke becoming a saved quantity, while the command receives a validated integer. Normalize only under the documented field contract; do not apply this numeric rule to unrelated sensitive text.

2. What should happen after a valid preview if the next draft is21?

Show worked solution

Under the shown contract, validation displays the range error and leaves the last accepted preview intact. A product can instead hide stale previews while editing, but that must be modeled deliberately. Invalid input must not silently clamp to20 or overwrite accepted state as21.

Key takeaways

  • A controlled input contains an editing draft
  • Test local rules separately from remote outcomes

Official references