# How to Use Validation in Retool Forms

- Tool: Retool
- Difficulty: Intermediate
- Time required: 15-20 min
- Compatibility: Retool Cloud and Self-hosted
- Last updated: March 2026

## TL;DR

Retool's built-in form validation is configured in the Inspector's Validation section for each input component. Set Required to true, choose a Pattern like Email or Regex, and set Min/Max Length. Prevent submission by binding the Submit button's Disabled property to {{ form1.invalid }}. Enable 'Validate inputs on submit' to delay error messages until submission is attempted.

## Configuring Built-in Validation Rules in Retool Forms

Retool provides a full set of built-in validation rules for form inputs that work without writing any JavaScript. The Required rule prevents empty submissions. Pattern rules enforce Email, URL, or custom Regex formats. Min and Max Length rules constrain string length. Min and Max Value rules work on numeric inputs. All rules are configured in the Inspector's Validation section and display inline error messages automatically.

This tutorial covers the Inspector-based built-in rules exclusively. For JavaScript-based custom validators — such as checking uniqueness against a database or cross-field validation — see the custom-validators tutorial. For overall form UX strategy (real-time vs on-submit feedback), see the user-input-validation tutorial.

You will learn the four most important rules, how to aggregate validation state with form1.invalid, how the 'Validate inputs on submit' toggle changes error visibility timing, and how required fields interact with the Hidden property for conditional forms.

## Before you start

- A Retool app with a Form component containing at least Text Input and Select components
- Basic familiarity with the Inspector panel
- An understanding of the {{ }} expression syntax

## Step-by-step guide

### 1. Open the Validation section in the Inspector for a Text Input

Select any Text Input component inside your Form. In the Inspector, scroll to the Validation section (below Interaction). You will see toggles and fields for Required, Min Length, Max Length, and Pattern. This section is available on all input component types: Text Input, Number Input, Select, Date Picker, File Picker, and more. Each input's validation state contributes to the parent Form's form1.invalid boolean.

**Expected result:** The Validation section is visible in the Inspector with Required toggle and Pattern dropdown.

### 2. Mark a field as Required

In the Validation section, toggle Required to ON. By default, the error message shown is 'This field is required'. Customize it by clicking the {{ fx }} icon next to the error message field and entering your own string, or a {{ }} expression for dynamic messages. Required fields display a red asterisk next to their label. When a required field is empty, it contributes to form1.invalid being true.

**Expected result:** The field shows a red asterisk and, when empty, contributes to form1.invalid = true.

### 3. Add an Email pattern validation

Select the email Text Input. In Validation → Pattern, choose 'Email' from the dropdown. Retool applies an RFC 5322-based regex automatically. Set the error message to 'Please enter a valid email address'. The pattern is evaluated on every keypress and when the field loses focus. If you need a stricter or looser email format than RFC 5322, switch to the 'Regex' option and write your own pattern.

```
// Retool's built-in email validation is equivalent to:
// Pattern (Regex): ^[^\s@]+@[^\s@]+\.[^\s@]+$

// For a custom domain restriction, use Regex pattern:
// ^[a-zA-Z0-9._%+-]+@yourcompany\.com$
// Error message: 'Must be a @yourcompany.com email address'
```

**Expected result:** Typing 'notanemail' in the field shows the validation error message. Typing 'user@example.com' clears it.

### 4. Set Min and Max Length constraints

For a password or username field, scroll to Min Length and Max Length in the Validation section. Set Min Length to 8 and Max Length to 64. Enter descriptive error messages: 'Password must be at least 8 characters' and 'Password must be 64 characters or fewer'. For Number Input components, use Min Value and Max Value instead of length constraints to bound the numeric range.

```
// Number Input validation (Min Value / Max Value)
// Example: quantity field must be 1-999
// Min Value: 1  →  Error: 'Quantity must be at least 1'
// Max Value: 999  →  Error: 'Quantity cannot exceed 999'

// Text Input regex for US phone number:
// Pattern → Regex: ^\+?1?[-.\s]?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}$
// Error: 'Enter a valid US phone number'
```

**Expected result:** A 5-character password triggers the Min Length error. A 100-character password triggers the Max Length error.

### 5. Disable the Submit button with form1.invalid

Select the Submit button inside the Form component. In Inspector → Interaction → Disabled, enter: {{ form1.invalid }}. Now the button is automatically greyed out whenever any validation rule fails across the entire form. This provides passive feedback — the button remains disabled, but no error messages appear until the user interacts with each field. Combine this with the 'Validate inputs on submit' toggle for a better UX pattern.

```
// Disabled expression on the Submit button:
{{ form1.invalid }}

// To add a tooltip explaining why it's disabled:
// Tooltip text: {{ form1.invalid ? 'Please fix the errors above before submitting' : '' }}

// Alternatively, check specific fields:
{{ emailInput.invalid || nameInput.value.length === 0 }}
```

**Expected result:** Submit button is greyed out on page load and activates only when all validation rules pass.

### 6. Enable 'Validate inputs on submit' for better UX

By default, validation error messages appear as soon as a field loses focus (on blur). For forms where you want to avoid showing errors before the user has had a chance to fill out the entire form, enable 'Validate inputs on submit'. This setting is on the Form component itself in Inspector → General → Validate inputs on submit. When enabled, inline error messages are suppressed until the user first clicks Submit, then all errors appear at once.

**Expected result:** No error messages show while filling out the form. Clicking Submit reveals all errors simultaneously, and the button disables.

### 7. Call form1.validate() in a JS Query for programmatic validation

In some flows you need to validate the form programmatically — for example, before advancing to step 2 of a multi-step form. Call form1.validate() in a JS Query. It returns a boolean: true if all validation rules pass, false if any fail. When false, all invalid fields also display their error messages. Use this in your 'Next Step' button handler to gate progression.

```
// JS Query: validateBeforeNextStep
// Trigger: 'Next' button click handler

const isValid = form1.validate();

if (!isValid) {
  utils.showNotification({
    title: 'Please fix the errors',
    description: 'All required fields must be filled before continuing.',
    notificationType: 'warning',
  });
  return;
}

// Advance to next step
await currentStepState.setValue(currentStepState.value + 1);
```

**Expected result:** Clicking Next without filling required fields shows all error messages and displays a notification. Filling them advances to the next step.

## Complete code example

File: `JS Query: validateAndSubmit`

```javascript
// validateAndSubmit — validates form, then submits if clean
// Trigger: Submit button click (or form onSubmit event)

// form1.validate() forces all error messages to display
const isValid = form1.validate();

if (!isValid) {
  utils.showNotification({
    title: 'Validation failed',
    description: 'Please fix the highlighted errors and try again.',
    notificationType: 'warning',
  });
  return;
}

// Extract validated data from the form
const data = form1.data;

try {
  await insertRecord.trigger({
    additionalScope: {
      name: data.nameInput,
      email: data.emailInput,
      phone: data.phoneInput,
      role: data.roleSelect,
    }
  });

  utils.showNotification({
    title: 'Success',
    description: 'Record saved successfully.',
    notificationType: 'success',
  });

  form1.reset();

} catch (err) {
  utils.showNotification({
    title: 'Submission error',
    description: err.message,
    notificationType: 'error',
  });
  throw err;
}
```

## Common mistakes

- **Setting a field as Required and Hidden simultaneously — the hidden required field blocks form1.invalid from clearing, so the form can never be submitted** — undefined Fix: Use expression mode on Required to mirror the visibility condition: if the field is Hidden when customerTypeSelect !== 'business', set Required to {{ customerTypeSelect.value === 'business' }}
- **Binding Submit Disabled to {{ form1.invalid }} but also having an event handler that calls form1.validate() on click — the button is disabled so the handler never fires** — undefined Fix: Choose one approach: either disable the button with form1.invalid (passive prevention) or leave it enabled and call form1.validate() in the click handler (active validation). Do not combine both.
- **Expecting form1.invalid to be false immediately after the page loads even with required fields — it starts as true because required fields are empty** — undefined Fix: This is correct behavior. Either set meaningful Default Values on required fields so they are not empty at load time, or add a flag variable that only enables validation after first submit attempt.
- **Using a regex pattern that includes anchors but forgetting Retool wraps patterns in anchors by default — results in double-anchoring and broken validation** — undefined Fix: Write the pattern body without leading ^ and trailing $ — Retool's Regex mode adds them automatically. Check the pattern with a test string before deploying.

## Best practices

- Use 'Validate inputs on submit' on the Form component to suppress premature error messages — this reduces user frustration on complex forms
- Always bind the Submit button's Disabled property to {{ form1.invalid }} to provide a passive visual cue that the form is not ready
- Write descriptive, action-oriented error messages: 'Enter a valid email address' rather than 'Invalid input'
- For conditional required fields, use expression mode on the Required toggle rather than hiding the field and hoping validation skips it
- Prefer built-in pattern rules (Email, URL) over hand-written regex for common formats — they are tested and maintained by Retool
- Combine built-in validation with custom validators (set via a JS expression on the Custom Validation field) for complex rules like uniqueness checks
- Test validation on mobile-sized preview — inline error messages can overflow on narrow layouts; adjust field widths accordingly

## Frequently asked questions

### Can I validate a Select component (dropdown) with built-in rules?

Yes. Select components have a Required toggle in their Validation section. When required, the Select is invalid if no option is selected. Pattern and length rules are not applicable to selects since they have predefined option values rather than free-text input.

### Does form1.invalid include validation for components outside the Form container?

No. form1.invalid only aggregates the validation state of components that are direct or nested children of that specific Form component. Components placed outside the Form are not included. If you have inputs outside a Form, check their individual .invalid properties manually.

### How do I show a validation summary at the top of the form instead of inline messages?

Add a Text component above the form fields and set its Hidden property to {{ !form1.invalid }}. In the text content, use a transformer or JS expression to map all invalid fields to their error messages and display them as a list. This supplements rather than replaces inline messages.

---

Source: https://www.rapidevelopers.com/retool-tutorial/how-to-use-validation-in-retool-forms
© RapidDev — https://www.rapidevelopers.com/retool-tutorial/how-to-use-validation-in-retool-forms
