> ## Documentation Index
> Fetch the complete documentation index at: https://docs.overflow.co/llms.txt
> Use this file to discover all available pages before exploring further.

# onChange

> Fires on every shopper interaction that changes an element's state.

`onChange` fires on every keystroke, mode toggle, blur, and (for compound elements) sub-element update. It is the source of truth for the shopper's current input and its validity.

## Payload

```typescript theme={null}
type OverflowChangeEvent<T> = {
  elementType: T;
  complete: boolean;
  value: ElementValueMap[T] | null;
  errors?: FieldError[]; // omitted when empty
};
```

Wallet elements and Checkout add extras (see below).

## Example

```javascript theme={null}
overflow.email()
  .on('onChange', ({ complete, value, errors }) => {
    submitBtn.disabled = !complete;
    renderInlineErrors(errors ?? []);
  })
  .mount('#email');
```

## Use `complete` to gate submission

`complete` is a single boolean that accounts for all per-field validation, mode toggles, and (for compound elements) sub-element state. Always drive your submit-button enabled state off `complete`; it is the only flag whose semantics are consistent across every element.

## `value` is the "what did the shopper type" channel

Do not infer validity from `value`. Some elements emit partial typed shapes mid-typing (for example, an address with some atoms filled and others empty). That is intentional and does not mean the value is valid.

See each element's reference page for its exact `onChange.value` shape.

## `errors` is omitted when empty

Code defensively:

```javascript theme={null}
element.on('onChange', ({ errors }) => {
  const list = errors ?? [];
  renderInlineErrors(list);
});
```

The same `FieldError[]` shape appears on `onError.fieldErrors` after a rejected submit. Reuse one renderer for both surfaces.

## Frequency

Handlers fire frequently (every keystroke). Debounce expensive side effects: analytics events, network calls, imperative DOM mutations that trigger reflow.

## Wallet extras

`applePay` and `googlePay` add a device-availability channel:

```typescript theme={null}
type WalletChangeExtras = {
  available: boolean;
  reason?: unknown; // populated when available: false
};
```

`value` on wallet `onChange` is always `null` and `complete` is always `false`; wallet completion is signalled by `onSubmit`, not by `complete`. Use `available` to hide the wallet button on unsupported devices.

## Checkout extras

`checkout` adds method-availability channels:

```typescript theme={null}
type CheckoutChangeExtras = {
  availableMethods: Array<'card' | 'bank' | 'applePay' | 'googlePay'>;
  unavailableMethods: Array<'card' | 'bank' | 'applePay' | 'googlePay'>;
};
```

`availableMethods` is the subset of `options.paymentMethods` that survived merchant settings and runtime wallet probes. `unavailableMethods` is the complement. Use both to render radios and "not available on this device" copy.

Checkout's `value` is always populated (never `null`). From mount onward it is at minimum `{ method, contact: {}, billingAddress: null, shippingAddress: null, [methodKey]: null }`.

## Bank

`bank` fires `onChange` when the shopper toggles between address-lookup and manual mode, when they complete linking, and on every manual-mode keystroke. See the [Bank reference](/payment-elements/elements/payment-methods/bank/reference) for the discriminated value shape.

## See also

* [Events overview](/payment-elements/events/overview)
* [`onSubmit`](/payment-elements/events/on-submit)
* [`onError`](/payment-elements/events/on-error)
* [Field errors](/payment-elements/events/field-errors)
