# Validation

_Validation is one of the key ways in which `Fielder` differentiates itself from other libraries._

## Validation events

Any provided validation function will be triggered immediately on either of these events:

- `mount` - on field mount/remount.
- `change` - on value change.
- `blur` - on blur event.
- `update` - on _any_ change event across the form (see [cross form validation](#cross-form-validation)).
- `submit` - on submit handler called.

## Basic validation

Validation is as simple as providing a function to `useField` which is called on each [validation event](#validation-events).

```tsx
const MyField = () => {
  const [passwordProps, passwordMeta] = useField({
    name: 'password'
    validate: validatePassword
  });

  return (
    <>
      <input type="password" {...passwordProps} />
      {passwordMeta.hasBlurred && passwordMeta.error}
    </>
  );
};

const validatePassword = ({ value }) => {
  if (!value || value.length < 8) {
    throw Error("Password must be 8 characters long");
  }
};
```

## Event specific validation

The `trigger` argument can be used to cater validation to specific events; such as triggering asynchronous validation on submit.

```tsx
const validateUsername = ({ trigger, value }) => {
  // Ignore other field updates
  if (trigger === 'update') {
    return;
  }

  // Ensure username exists (mount, change, blur, submit)
  if (!value) {
    throw Error('Username is required');
  }

  // Check if username is taken (submit)
  if (trigger === 'submit') {
    return isUsernameFree(value).then((isFree) => {
      if (!isFree) {
        throw Error('Username is already taken');
      }
    });
  }
};
```

## Cross form validation

The `form` argument can be used to conditionally validate a field based on other field values in the form.

```tsx
const validatePasswordConfirmation = ({ value, form }) => {
  // Wait for password validation first
  if (!form.password.isValid) {
    return;
  }

  if (value !== form.password.value) {
    throw Error('Password confirmation does not match');
  }
};
```

## Cross source validation

Memoised validation functions dependent on state outside of the form can be used.

> Changes to validation functions will retrigger the last mount/change/blur event

```tsx
const { addressIsRequired } = useSomeExternalState();

const [fieldProps, fieldMeta] = useField({
  name: 'address'
  validate: useCallback(({ value }) => {
    if (addressIsRequired && !value) {
      throw Error("Address is required");
    }
  }, [addressIsRequired])
});
```
