---
name: "[up-validate]"
area: "API"
kind: "HTML attribute"
parent: "up.form module"
url: "https://unpoly.com/api/up-validate"
---
<nav aria-label="Unpoly docs">[All docs](https://unpoly.com/index.md) · [up.form module](https://unpoly.com/api/up.form.md)</nav>

# [up-validate]

Renders a new form state when a field changes, to [show validation errors](https://unpoly.com/learn/validation.md#validating-after-changing-a-field) or update [dependent elements](https://unpoly.com/learn/reactive-server-forms.md).

When a form field with an `[up-validate]` attribute is changed, the form is submitted to the server which is expected to render a new form state from its current field values. The [form group](https://unpoly.com/api/up-form-group.md) around the changed field is updated with the server response. This quickly signals whether a change is valid, without the need to scroll for error messages or to backtrack to fields completed earlier.

> <nav aria-label="Guides">
>
> - [Learn: Validating forms](https://unpoly.com/learn/validation.md)
> - [Learn: Reactive server forms](https://unpoly.com/learn/reactive-server-forms.md)
>
> </nav>
>
> #### Note
>
> `[up-validate]` is a tool to implement highly dynamic forms that must update _as the user is completing fields_.
> If you only need to [validate forms after submission](https://unpoly.com/learn/validation.md#validating-after-submission), you don't need `[up-validate]`.

<nav aria-label="Contents">

#### Contents

- [Marking fields for validation](#marking-fields-for-validation)
- [Backend protocol](#backend-protocol)
- [How validation results are displayed](#how-validation-results-are-displayed)
- [Updating dependent elements](#updating-dependent-elements)
- [Validating while typing](#validating-while-typing)
- [Preventing race conditions](#preventing-race-conditions)
- [Validating multiple fields](#validating-multiple-fields)
- [Validating against other URLs](#urls)
- [Programmatic validation](#programmatic-validation)
- [Modifying attributes](#attributes)

</nav>

## Marking fields for validation {#marking-fields-for-validation}

Let's look at a standard registration form that asks for an e-mail and password. The form is organized into [form groups](https://unpoly.com/api/up-form-group.md) of labels, inputs and an optional error message:

```html
<form method="post" action="/users">

  <fieldset>
    <label for="email">E-mail</label>
    <input type="text" id="email" name="email">
  </fieldset>

  <fieldset>
    <label for="password">Password</label>
    <input type="password" id="password" name="password">
  </fieldset>

  <button type="submit">Register</button>

</form>
```

We have some data constraints that we want to validate as the user is filling in fields:

- When the user changes the `email` field, we want to validate that the e-mail address is formatted correctly and is still available.
- When the user changes the `password` field, we want to validate the minimum password length.

If validation fails, we want to show validation errors _as soon as the user blurs the field_.

We can implement this by giving both fields an `[up-validate]` attribute:

```html
<form method="post" action="/users">

  <fieldset>
    <label for="email">E-mail</label>
    <input type="text" id="email" name="email" up-validate>
  </fieldset>

  <fieldset>
    <label for="password">Password</label>
    <input type="password" id="password" name="password" up-validate>
  </fieldset>

  <button type="submit">Register</button>

</form>
```

Whenever a field with `[up-validate]` changes, the form is submitted to its `[action]` path with an additional [`X-Up-Validate`](https://unpoly.com/api/X-Up-Validate.md) HTTP header.

Read on to learn [how a validation request is sent to the server](#backend-protocol), and [how the server response is displayed](#how-validation-results-are-displayed).

## Backend protocol {#backend-protocol}

When the user changes the `email` field in the registration form above, the following request will be sent:

```http
POST /users HTTP/1.1
X-Up-Validate: email
X-Up-Target: fieldset:has(#email)
Content-Type: application/x-www-form-urlencoded

email=foo%40bar.com&password=secret
```

Upon seeing an [`X-Up-Validate`](https://unpoly.com/api/X-Up-Validate.md) header, the server is expected to validate (but not commit) the form submission and render a new form state from the request parameters.

This requires a change in the backend code that handles the form's `[action]` path. Until now, the backend only had to handle two cases:

1. The form was submitted with valid data. We create a new account and sign in the user.
2. The form submission failed due to an invalid email or password. We re-render the form with error messages.

A [Ruby on Rails](https://rubyonrails.org/) implementation would look like this:

```ruby
class UsersController < ApplicationController

  def create
    # Instantiate model from request parameters
    user_params = params.permit(:email, :password)
    @user = User.new(user_params)

    if @user.save
      # Form is submitted successfully
      sign_in @user
    else
      # Submission failed
      render 'form', status: :unprocessable_entity
    end

  end

end
```

The examples use Ruby on Rails, but work similarly with any other backend.

To honor the validation protocol, our backend needs to handle a third case:

3. When seeing an [`X-Up-Validate`](https://unpoly.com/api/X-Up-Validate.md) header, render a new form state from request parameters

In our example backend above, this change could look like this:

```ruby
class UsersController < ApplicationController

  def create
    # Instantiate model from request parameters
    user_params = params.permit(:email, :password)
    @user = User.new(user_params)

    if request.headers['X-Up-Validate']
      @user.validate
      render 'form'
    elsif @user.save
      # Form is submitted successfully
      sign_in @user
    else
      # Submission failed
      render 'form', status: :unprocessable_entity
    end

  end

end
```

> #### Tip
>
> If you're using Python with Django, you may find the [`django-forms-dynamic`](https://github.com/dabapps/django-forms-dynamic) package useful to implement this pattern.

The server is free to respond with any HTTP status code, regardless of the validation result. Unpoly will always consider a validation request to be successful, even if the server responds with a non-2xx status code.

Upon seeing an [`X-Up-Validate`](https://unpoly.com/api/X-Up-Validate.md) header, the server now renders a new form state from request parameters, showing eventual validation errors and updating [dependent elements](https://unpoly.com/learn/reactive-server-forms.md):

```html
<form method="post" action="/users">

  <fieldset>
    <label for="email">E-mail</label>
    <input type="text" id="email" name="email" value="foo@bar.com" up-validate>
    <div class="error">E-mail has already been taken!</div>
  </fieldset>

  <fieldset>
    <label for="password">Password</label>
    <input type="password" id="password" name="password" value="secret" up-validate>
    <div class="error">Password is too short!</div>
  </fieldset>

</form>
```

## How validation results are displayed {#how-validation-results-are-displayed}

`[up-validate]` always submits the entire form with its current field values to the form's `[action]` path. Typically, only a fragment of the form is updated with the response. This minimizes the chance for loss of transient state like scroll positions, cursor selection, or user input while the request is in flight.

By default, Unpoly will only update the closest [form group](https://unpoly.com/api/up-form-group.md) around the validating field. In the [example above](#marking-fields-for-validation), after changing the `email` field, only the `<fieldset>` around the field will be updated.

If the form is not structured into groups, the entire form will be updated.

### Updating a different fragment {#target}

If you don't want to update the field's form group, you can set the `[up-validate]` attribute to any [target selector](https://unpoly.com/learn/targeting-fragments.md):

```html
<input name="email" up-validate=".email-errors">
<div class="email-errors"></div>
```

You may [update multiple fragments](https://unpoly.com/learn/targeting-fragments.md#multiple) by separating their target selectors with a comma:

```html
<input name="email" up-validate=".email-errors, .base-errors">
```

To update another fragment _in addition_ to the field's form group, include the group in the target list.
You can refer to the changed field as [`:origin`](https://unpoly.com/api/origin.md):

```html
<fieldset>
  <input name="email" up-validate="fieldset:has(:origin), .base-errors">
</fieldset>
```

## Updating dependent elements {#updating-dependent-elements}

The `[up-validate]` attribute is a useful tool to partially update a form when an element depends on the value of another field.

See [Reactive server forms](https://unpoly.com/learn/reactive-server-forms.md) for more details and examples.

## Validating while typing {#validating-while-typing}

By default, `[up-validate]` reacts to the `change` event that is emitted when the user is done editing and focuses the next field.

We can validate while the user is typing by setting an `[up-watch-event="input"]` attribute:

```html
<input name="email" up-validate up-watch-event="input" up-watch-delay="100" up-keep>
```

Note that we set some additional [watch options](https://unpoly.com/learn/watch-options.md) to improve the experience:

- The [`[up-watch-delay]`](https://unpoly.com/learn/watch-options.md#debouncing) attribute delays validation until the user has stopped typing for 100 milliseconds.
- The [`[up-keep]`](https://unpoly.com/api/up-keep.md) attribute keeps additional user input while the validation request is in flight.

If you're using this pattern a lot, you may want to configure a [macro](https://unpoly.com/api/up.macro.md) for it.

## Preventing race conditions {#preventing-race-conditions}

Unpoly sends one validation request per form at a time and batches the rest.

See [preventing race conditions](https://unpoly.com/learn/reactive-server-forms.md#race-conditions) for more details.

## Validating multiple fields {#validating-multiple-fields}

You can set `[up-validate]` on any element to validate _all contained fields_ on change.

In the [example above](#marking-fields-for-validation), instead of setting `[up-validate]` on each individual `<input>`, we can also set it on the `<form>`:

```html
<form method="post" action="/users" up-validate>

  <fieldset>
    <label for="email">E-mail</label>
    <input type="text" id="email" name="email"> <!-- chip "will validate" -->
  </fieldset>

  <fieldset>
    <label for="password">Password</label>
    <input type="password" id="password" name="password"> <!-- chip "will validate" -->
  </fieldset>

  <button type="submit">Register</button>

</form>
```

You can also set `[up-validate]` on an intermediate container to only validate its children:

```html
<form method="post" action="/users">

  <div up-validate>
    <fieldset>
      <label for="email">E-mail</label>
      <input type="text" id="email" name="email"> <!-- chip "will validate" -->
    </fieldset>

    <fieldset>
      <label for="password">Password</label>
      <input type="password" id="password" name="password"> <!-- chip "will validate" -->
    </fieldset>
  </div>

  <fieldset>
    <label for="name">Name</label>
    <input type="text" id="name" name="name"> <!-- chip "will NOT validate" -->
  </fieldset>

  <button type="submit">Register</button>

</form>
```

### Validating radio buttons {#validating-radio-buttons}

Multiple radio buttons with the same `[name]` produce a single value for the form.

To validate a group of radio buttons, use the `[up-validate]` attribute on an element that contains all radio button elements with a given name:

```html
<fieldset up-validate>
  <input type="radio" name="format" value="html"> HTML format
  <input type="radio" name="format" value="pdf"> PDF format
  <input type="radio" name="format" value="txt"> Text format
</fieldset>
```

## Validating against other URLs {#urls}

By default, validation requests will use `[method]` and `[action]` attributes from the form element.

You can validate against another server endpoint by setting `[up-validate-url]` and `[up-validate-method]` attributes:

```html
<form method="post" action="/order" up-validate-url="/validate-order">
  ...
</form>
```

To have individual fields validate against different URLs, you can also set `[up-validate-url]` on a field:

```html
<form method="post" action="/register">
  <input name="email" up-validate-url="/validate-email">
  <input name="password" up-validate-url="/validate-password">
</form>
```

Multiple validations to the same URL will be [batched together](https://unpoly.com/api/up.validate.md#batching).

## Programmatic validation {#programmatic-validation}

To update form fragments from your JavaScript, use the [`up.validate()`](https://unpoly.com/api/up.validate.md) function. You may combine `[up-validate]` and [`up.validate()`](https://unpoly.com/api/up.validate.md) within the same form. Their updates will be [batched together](https://unpoly.com/api/up.validate.md#batching) in order to [prevent race conditions](https://unpoly.com/learn/reactive-server-forms.md#race-conditions).

---

## Modifying attributes {#attributes}

### Targeting {#attributes-targeting}

#### [up-validate] {#up-validate}

(optional)

The [target selector](https://unpoly.com/learn/targeting-fragments.md) to update with the server response.

Defaults to the closest [form group](https://unpoly.com/api/up-form-group.md) around the validating field.

You can set another selector to [update a different fragment](https://unpoly.com/api/up-validate.md#target). To refer to the changed field, use the [`:origin`](https://unpoly.com/api/origin.md) pseudo-selector.

### Observed events {#attributes-observed-events}

#### [up-watch-event='change'] {#up-watch-event}

(optional)

The type of event to watch.

See [which events to watch](https://unpoly.com/learn/watch-options.md#events).

#### [up-watch-delay=0] {#up-watch-delay}

(optional)

The number of milliseconds to wait after a change.

This can be used to batch multiple events within a short time span. See [debouncing callbacks](https://unpoly.com/learn/watch-options.md#debouncing).

### Request {#attributes-request}

#### [up-validate-url] {#up-validate-url}

(optional)

The URL to which to submit the validation request.

By default, Unpoly will use the form's `[action]` attribute.

See [Validating against other URLs](https://unpoly.com/api/up-validate.md#urls).

#### [up-validate-method] {#up-validate-method}

(optional)

The method to use for submitting the validation request.

By default, Unpoly will use the form's `[method]` attribute.

See [Validating against other URLs](https://unpoly.com/api/up-validate.md#urls).

#### [up-validate-params] (Experimental) {#up-validate-params}

(optional)

Additional [Form parameters](https://unpoly.com/api/up.Params.md) that should be sent as the request's [query string](https://en.wikipedia.org/wiki/Query_string) or payload.

The given value will be added to params [parsed](https://unpoly.com/api/up.Params.fromForm.md) from the form's input fields. If a param with the same name already existed in the form, it will be deleted and overridden with the given value.

#### [up-validate-headers] (Experimental) {#up-validate-headers}

(optional)

A [relaxed JSON](https://unpoly.com/api/relaxed-json.md) object with additional request headers.

By default, Unpoly will send an [`X-Up-Validate`](https://unpoly.com/api/X-Up-Validate.md) header so the server can [distinguish the validation request from a regular form submission](#backend-protocol).

#### [up-validate-batch='true'] {#up-validate-batch}

(optional)

Whether to [consolidate multiple validations into a single request](https://unpoly.com/api/up.validate.md#batching).

Defaults to [`up.form.config.validateBatch`](https://unpoly.com/api/up.form.config.md#config.validateBatch), which defaults to `true`.

### Loading state {#attributes-loading-state}

#### [up-watch-disable] {#up-watch-disable}

(optional)

Whether to [disable fields](https://unpoly.com/learn/disabling-forms.md) while a request is loading.

See [disabling fields while working](https://unpoly.com/learn/watch-options.md#disabling).

#### [up-watch-placeholder] (Experimental) {#up-watch-placeholder}

(optional)

A [placeholder](https://unpoly.com/learn/placeholders.md) to show within the targeted fragment while a request is loading.

See [showing loading state while working](https://unpoly.com/learn/watch-options.md#loading-state).

#### [up-watch-preview] (Experimental) {#up-watch-preview}

(optional)

One or more [previews](https://unpoly.com/learn/previews.md) that temporarily change the page while a request is loading.

See [showing loading state while working](https://unpoly.com/learn/watch-options.md#loading-state).

#### [up-watch-feedback='true'] {#up-watch-feedback}

(optional)

Whether to set [feedback classes](https://unpoly.com/learn/feedback-classes.md) while a request is loading.

