Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

React Native has no HTML <form> element. Connect each TextInput to a Formik field, display Yup errors when the field is appropriately touched, and invoke Formik’s handleSubmit from a native Button. Hooks such as useField change how you compose the code, not how native text events work.

The native/Formik mental model

A web form submits through a DOM form element. React Native instead exposes native events: onChangeText receives the current string and onSubmitEditing fires when the keyboard’s submit action is used. Formik’s React Native guide therefore passes handleSubmit to Button onPress, rather than to an HTML submit event.

For each control, keep four connections explicit:

  • Value: value={values.email}.
  • Change: onChangeText={handleChange('email')}, or setFieldValue('email', text).
  • Touch: onBlur={handleBlur('email')}, or setFieldTouched('email', true).
  • Submission: <Button title="Submit" onPress={handleSubmit} />.

Formik supports synchronous and asynchronous validation at field or form level. A Yup object supplied through validationSchema produces an error object whose keys match your values.

A complete Formik and Yup screen

The following component uses native controls, a Yup schema, touched-aware errors, and an asynchronous submit function. Install compatible current releases of formik, yup, and your React Native project dependencies; this guide intentionally does not prescribe package versions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import React from 'react';
import { Alert, Button, StyleSheet, Text, TextInput, View } from 'react-native';
import { Formik } from 'formik';
import * as Yup from 'yup';

const SignupSchema = Yup.object({
  name: Yup.string()
    .trim('Name cannot contain only spaces')
    .required('Name is required')
    .min(2, 'Use at least 2 characters')
    .max(80, 'Use 80 characters or fewer'),
  email: Yup.string()
    .trim()
    .email('Enter a valid email address')
    .required('Email is required'),
  password: Yup.string()
    .required('Password is required')
    .min(8, 'Use at least 8 characters')
    .max(128, 'Use 128 characters or fewer'),
  confirmPassword: Yup.string()
    .oneOf([Yup.ref('password')], 'Passwords must match')
    .required('Confirm your password')
});

export default function SignupScreen() {
  return (
    <Formik
      initialValues={{ name: '', email: '', password: '', confirmPassword: '' }}
      validationSchema={SignupSchema}
      onSubmit={async (values, { setSubmitting, resetForm }) => {
        try {
          // Replace with your API request. Do not log passwords.
          await createAccount(values);
          Alert.alert('Account created');
          resetForm();
        } catch (error) {
          Alert.alert('Unable to create account', 'Try again later.');
        } finally {
          setSubmitting(false);
        }
      }}
    >
      {({ handleChange, handleBlur, handleSubmit, values, errors, touched, isSubmitting }) => (
        <View style={styles.container}>
          <TextInput
            style={styles.input}
            placeholder="Name"
            value={values.name}
            onChangeText={handleChange('name')}
            onBlur={handleBlur('name')}
            autoCapitalize="words"
            textContentType="name"
          />
          {touched.name && errors.name ? <Text style={styles.error}>{errors.name}</Text> : null}

          <TextInput
            style={styles.input}
            placeholder="Email"
            value={values.email}
            onChangeText={handleChange('email')}
            onBlur={handleBlur('email')}
            keyboardType="email-address"
            autoCapitalize="none"
            autoCorrect={false}
            textContentType="emailAddress"
          />
          {touched.email && errors.email ? <Text style={styles.error}>{errors.email}</Text> : null}

          <TextInput
            style={styles.input}
            placeholder="Password"
            value={values.password}
            onChangeText={handleChange('password')}
            onBlur={handleBlur('password')}
            secureTextEntry
            textContentType="newPassword"
          />
          {touched.password && errors.password ? <Text style={styles.error}>{errors.password}</Text> : null}

          <TextInput
            style={styles.input}
            placeholder="Confirm password"
            value={values.confirmPassword}
            onChangeText={handleChange('confirmPassword')}
            onBlur={handleBlur('confirmPassword')}
            secureTextEntry
            textContentType="newPassword"
            onSubmitEditing={() => handleSubmit()}
            returnKeyType="done"
          />
          {touched.confirmPassword && errors.confirmPassword ? (
            <Text style={styles.error}>{errors.confirmPassword}</Text>
          ) : null}

          <Button
            title={isSubmitting ? 'Submitting…' : 'Submit'}
            onPress={() => handleSubmit()}
            disabled={isSubmitting}
          />
        </View>
      )}
    </Formik>
  );
}

const styles = StyleSheet.create({
  container: { padding: 16, gap: 8 },
  input: { borderWidth: 1, borderColor: '#999', borderRadius: 6, padding: 12 },
  error: { color: '#b00020', marginBottom: 4 }
});

async function createAccount(values) {
  // Send values to your server over HTTPS and handle its response.
}

onSubmitEditing is optional; it gives the keyboard’s action key a submit path. Keep the visible button as the primary, accessible submission control. Disable it while an asynchronous request is pending to avoid duplicate requests.

Choosing when validation appears

Formik validates after change and blur by default. That can be useful for immediate feedback, but password and cross-field rules may feel noisy while a user is still typing. Choose deliberately:

Validate on change

Use the default when short, local rules benefit from immediate feedback. A minimum-length message can appear after the first keystroke, so consider showing it only after the field has been touched.

Validate on blur

Set validateOnChange={false} when users should finish a field before seeing errors. Keep validateOnBlur enabled and render only when touched[field] && errors[field].

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Validate on submit

Set both validateOnChange={false} and validateOnBlur={false} for submit-focused flows. Before displaying a summary, mark fields touched with setTouched so users can find each problem.

Mixed behavior

A common compromise is blur validation for most fields, change validation after an error exists, and submit validation for the complete schema. Whatever policy you choose, ensure server errors are mapped separately from client-side Yup errors.

Hooks and reusable native fields

Formik’s useField, useFormik, and useFormikContext are composition APIs. They do not replace onChangeText or create a web-style submit event. A reusable field can centralize value, touch, and error rendering:

import React from 'react';
import { Text, TextInput, View } from 'react-native';
import { useField } from 'formik';

export function FormikTextInput({ name, ...props }) {
  const [field, meta, helpers] = useField(name);
  const showError = meta.touched && Boolean(meta.error);

  return (
    <View>
      <TextInput
        {...props}
        value={field.value == null ? '' : String(field.value)}
        onChangeText={text => helpers.setValue(text)}
        onBlur={() => helpers.setTouched(true)}
      />
      {showError ? <Text style={{ color: '#b00020' }}>{meta.error}</Text> : null}
    </View>
  );
}

Use useFormik when you want the Formik bag in a component without render props, and useFormikContext for descendants such as a submit toolbar. Hooks must follow React’s hook rules and run beneath the corresponding Formik provider.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Yup schemas versus custom validators

Approach Best fit Trade-off
Yup object schema Shared field rules, nested values, and consistent messages Adds a schema dependency and requires messages that match product language
Synchronous custom validation Small forms or rules that are easier to express directly You maintain the error-object shape and avoid duplicated logic manually
Asynchronous validation Checks involving a server, such as account availability Needs loading, cancellation or stale-response handling, and server-error mapping

Formik supports field-level and form-level validators in both synchronous and asynchronous forms. Use one source of truth for constraints such as required, minimum, maximum, and email rules; do not rely on a client check as authorization—repeat security validation on the server.

Accessibility and native details

  • Set a useful placeholder but provide a persistent label with Text; placeholders disappear while typing.
  • Use accessible, accessibilityLabel, and platform-appropriate hints where a label is not obvious.
  • Choose keyboardType, autoCapitalize, autoCorrect, secureTextEntry, and textContentType to match the data.
  • Keep error text adjacent to its field and use sufficient color contrast; color alone should not communicate failure.
  • For long forms, place inputs in a keyboard-aware scrolling layout and preserve values when navigating back.

Troubleshooting common failures

The button does nothing

Confirm that onPress calls handleSubmit and that the button is not permanently disabled. Validation errors prevent onSubmit; temporarily render the errors object or log non-sensitive field state while diagnosing.

The value is always empty

Ensure the field name exists in initialValues, the input is controlled with the matching value, and onChangeText receives Formik’s handler rather than a web onChange event.

Errors never appear

Call handleBlur('field') or setFieldTouched, and render errors conditionally from both touched and errors. Check that the Yup schema key exactly matches the value key.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Errors appear too early

Adjust validateOnChange, or gate rendering until blur. You can also keep validation active while showing only a concise message after the user has interacted.

Async responses overwrite newer input

Track the value associated with each request, cancel requests where your client supports cancellation, or ignore a response that is no longer current. Never expose raw server exceptions or sensitive values in an error message.

Keyboard submission behaves inconsistently

Set an appropriate returnKeyType, wire onSubmitEditing to handleSubmit on the final input, and retain the visible Button for users who do not use the keyboard action.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Testing and production checks

  • Exercise empty, whitespace-only, boundary-length, malformed-email, mismatched-password, and valid inputs.
  • Verify blur and submit behavior on both iOS and Android, including a hardware keyboard.
  • Test slow, failed, and duplicated submissions; restore the button after every settled request.
  • Confirm API errors are distinguishable from Yup errors and that navigation does not lose unsaved values.
  • Review accessibility focus, labels, error announcements, and dark-mode contrast.

Or skip the browser setup

If your workflow also needs rendered website screenshots for documentation, QA, or an AI-assisted pipeline, ScreenshotNeo provides a one-request API. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the complete parameter reference in the ScreenshotNeo documentation. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. Plans include 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

FAQ

Can I use Formik without Yup?

Yes. Supply synchronous or asynchronous field-level or form-level validator functions and return an errors object matching your values.

Should validation messages come from the server?

Use client validation for fast feedback, but treat server validation as authoritative for permissions, uniqueness, and security-sensitive rules.

Is a hook-based form a different native integration?

No. Whether you use render props or Formik hooks, native inputs still provide onChangeText, blur, and keyboard-submit events.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can I use Formik without Yup?

Yes. Formik accepts synchronous or asynchronous field-level and form-level validator functions.

Should validation messages come from the server?

Use client checks for feedback, while the server remains authoritative for security, permissions, and uniqueness.

Do Formik hooks change React Native input events?

No. Hooks alter composition; TextInput still uses onChangeText, onBlur, and optional onSubmitEditing.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.