Labs ICT
Pro Login

Form Validation

Validating user input effectively.

Why Validate?

Form validation ensures that users enter data in the correct format before it's sent to the server. Without validation, you might get empty fields, invalid emails, passwords that are too short, or other problematic data. Validation improves data quality and user experience by catching errors early.

There are two types of validation: client-side (in the app) and server-side (on the server). You should always do both. Client-side validation gives instant feedback, while server-side validation is the final safety net.

Basic Validation

Here's a simple form with validation for required fields and email format:

import React, { useState } from 'react';
import { View, Text, TextInput, Button, StyleSheet } from 'react-native';

function ValidatedForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [errors, setErrors] = useState({});

  const validate = () => {
    const newErrors = {};

    if (!email) {
      newErrors.email = 'Email is required';
    } else if (!/\S+@\S+\.\S+/.test(email)) {
      newErrors.email = 'Email is invalid';
    }

    if (!password) {
      newErrors.password = 'Password is required';
    } else if (password.length < 6) {
      newErrors.password = 'Password must be at least 6 characters';
    }

    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleSubmit = () => {
    if (validate()) {
      console.log('Form is valid:', { email, password });
    }
  };

  return (
    <View style={styles.container}>
      <TextInput
        style={[styles.input, errors.email && styles.inputError]}
        placeholder="Email"
        value={email}
        onChangeText={setEmail}
      />
      {errors.email && <Text style={styles.error}>{errors.email}</Text>}

      <TextInput
        style={[styles.input, errors.password && styles.inputError]}
        placeholder="Password"
        value={password}
        onChangeText={setPassword}
        secureTextEntry
      />
      {errors.password && <Text style={styles.error}>{errors.password}</Text>}

      <Button title="Submit" onPress={handleSubmit} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { padding: 20 },
  input: { height: 50, borderWidth: 1, borderColor: '#ccc', borderRadius: 8, paddingHorizontal: 15, marginBottom: 5 },
  inputError: { borderColor: 'red' },
  error: { color: 'red', fontSize: 14, marginBottom: 10 },
});

export default ValidatedForm;

The validate function checks each field and populates an errors object. If there are no errors, the form is valid. The input border turns red when there's an error, and the error message appears below. This gives users clear feedback about what needs to be fixed.

Real-Time Validation

You can also validate as the user types, providing instant feedback. This is more user-friendly than waiting until submission.

function RealTimeForm() {
  const [email, setEmail] = useState('');
  const [emailError, setEmailError] = useState('');

  const handleEmailChange = (text) => {
    setEmail(text);
    if (text && !/\S+@\S+\.\S+/.test(text)) {
      setEmailError('Please enter a valid email');
    } else {
      setEmailError('');
    }
  };

  return (
    <View style={{ padding: 20 }}>
      <TextInput
        style={{ borderColor: emailError ? 'red' : '#ccc', borderWidth: 1, padding: 10 }}
        placeholder="Email"
        value={email}
        onChangeText={handleEmailChange}
        keyboardType="email-address"
      />
      {emailError ? (
        <Text style={{ color: 'red' }}>{emailError}</Text>
      ) : email ? (
        <Text style={{ color: 'green' }}>Looks good!</Text>
      ) : null}
    </View>
  );
}

Real-time validation checks the input on every change and updates the error message immediately. This helps users correct mistakes as they type instead of being surprised at submission. Show positive feedback too — a green checkmark or "Looks good" message when the input is valid.

Validation Libraries

For complex forms with many validation rules, consider using a validation library. Libraries like yup and formik provide powerful validation schemas that reduce boilerplate code.

// Using yup for validation
import * as yup from 'yup';

const schema = yup.object().shape({
  email: yup.string().email('Invalid email').required('Email is required'),
  password: yup.string().min(6, 'Password must be at least 6 characters').required('Password is required'),
  age: yup.number().min(18, 'Must be at least 18').required('Age is required'),
});

const validateForm = async (data) => {
  try {
    await schema.validate(data, { abortEarly: false });
    return { valid: true, errors: {} };
  } catch (err) {
    const errors = {};
    err.inner.forEach(e => {
      errors[e.path] = e.message;
    });
    return { valid: false, errors };
  }
};

Validation libraries handle common patterns like email validation, password strength, minimum lengths, and custom rules. They reduce the amount of validation code you need to write and maintain. For simple forms, manual validation is fine. For complex forms, a library saves time and reduces errors.