Skip to content

Ext JS Forms — Input Fields, Validation, and Data Binding

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Ext JS Forms. We cover key concepts, practical examples, and best practices to help you master this topic.

Ext JS Forms provide a structured way to collect and validate user input with field types, built-in validators, layout management, and automatic binding to data models.

What You'll Learn

  • Configuring form fields and layouts
  • Built-in and custom field validation
  • Binding forms to Models and Stores
  • Handling form submission and reset
  • Dynamic form manipulation

Why It Matters

Enterprise applications heavily depend on forms for data entry — user registration, order creation, settings panels, and search filters. Ext JS Forms handle client-side validation, layout consistency, and server communication without manual wiring.

Real-World Use

A customer support ticket form with text fields for subject and description, a combo box for priority, radio buttons for category, checkboxes for tags, and date picker for deadline — all validated before submission.

Form Architecture

flowchart TD
    A[Form Panel] --> B[Field Container]
    A --> C[Fieldset]
    A --> D[Buttons]
    B --> E[TextField]
    B --> F[ComboBox]
    B --> G[Checkbox]
    B --> H[NumberField]
    B --> I[DateField]
    A --> J[Model Binding]
    J --> K[Load Record]
    J --> L[Update Record]
    style A fill:#e6f3ff,stroke:#4a90d9,stroke-width:2px

Basic Form Configuration

Ext.create('Ext.form.Panel', {
  title: 'User Registration',
  width: 450,
  bodyPadding: 15,
  url: '/api/users',
  defaults: {
    anchor: '100%',
    labelWidth: 120
  },
  items: [{
    xtype: 'textfield',
    fieldLabel: 'Full Name',
    name: 'name',
    allowBlank: false
  }, {
    xtype: 'textfield',
    fieldLabel: 'Email',
    name: 'email',
    vtype: 'email',
    allowBlank: false
  }, {
    xtype: 'numberfield',
    fieldLabel: 'Age',
    name: 'age',
    minValue: 1,
    maxValue: 150
  }, {
    xtype: 'combobox',
    fieldLabel: 'Country',
    name: 'country',
    store: ['USA', 'Canada', 'UK', 'Australia'],
    queryMode: 'local',
    typeAhead: true
  }, {
    xtype: 'checkboxgroup',
    fieldLabel: 'Interests',
    columns: 2,
    items: [
      { boxLabel: 'Technology', name: 'interest-tech', inputValue: 'tech' },
      { boxLabel: 'Science', name: 'interest-science', inputValue: 'science' },
      { boxLabel: 'Sports', name: 'interest-sports', inputValue: 'sports' },
      { boxLabel: 'Music', name: 'interest-music', inputValue: 'music' }
    ]
  }],
  buttons: [{
    text: 'Submit',
    handler: function() {
      var form = this.up('form').getForm();
      if (form.isValid()) {
        form.submit({
          success: function() { Ext.Msg.alert('Success', 'User created'); },
          failure: function() { Ext.Msg.alert('Error', 'Submission failed'); }
        });
      }
    }
  }, {
    text: 'Reset',
    handler: function() {
      this.up('form').getForm().reset();
    }
  }],
  renderTo: Ext.getBody()
});

Expected output: A form panel with text fields, combo box, number field, and checkbox group. Submit validates all fields before sending to the server. Reset clears all values.

Field Validation

Ext.create('Ext.form.Panel', {
  items: [{
    xtype: 'textfield',
    fieldLabel: 'Username',
    name: 'username',
    allowBlank: false,
    minLength: 3,
    maxLength: 20,
    regex: /^[a-zA-Z0-9_]+$/,
    regexText: 'Only letters, numbers, and underscores allowed'
  }, {
    xtype: 'textfield',
    fieldLabel: 'Email',
    name: 'email',
    vtype: 'email' // Built-in email validation
  }, {
    xtype: 'textfield',
    fieldLabel: 'Confirm Email',
    name: 'confirmEmail',
    vtype: 'email',
    validator: function(value) {
      var email = this.up('form').down('[name=email]').getValue();
      return value === email ? true : 'Emails must match';
    }
  }, {
    xtype: 'textfield',
    fieldLabel: 'Password',
    inputType: 'password',
    name: 'password',
    minLength: 8,
    // Custom vtype
    vtype: 'passwordStrength'
  }]
});

// Register custom vtype
Ext.apply(Ext.form.field.VTypes, {
  passwordStrength: function(val) {
    return /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/.test(val);
  },
  passwordStrengthText: 'Must contain uppercase, lowercase, and number'
});

Expected output: Fields validate on blur and on form submit. The username enforces pattern, email uses built-in vtype, confirm email runs a custom validator, and password uses a custom vtype for strength.

Form Binding to a Model

Ext.define('MyApp.model.Product', {
  extend: 'Ext.data.Model',
  fields: [
    { name: 'id', type: 'int' },
    { name: 'name', type: 'string' },
    { name: 'price', type: 'float' },
    { name: 'category', type: 'string' },
    { name: 'active', type: 'bool' }
  ]
});

// Create the form with loadRecord / updateRecord
var formPanel = Ext.create('Ext.form.Panel', {
  title: 'Edit Product',
  bodyPadding: 15,
  items: [{
    xtype: 'textfield',
    fieldLabel: 'Product Name',
    name: 'name'
  }, {
    xtype: 'numberfield',
    fieldLabel: 'Price',
    name: 'price',
    step: 0.01
  }, {
    xtype: 'combobox',
    fieldLabel: 'Category',
    name: 'category',
    store: ['Electronics', 'Clothing', 'Food']
  }, {
    xtype: 'checkbox',
    fieldLabel: 'Active',
    name: 'active'
  }],
  buttons: [{
    text: 'Load',
    handler: function() {
      var record = Ext.create('MyApp.model.Product', {
        id: 1, name: 'Laptop', price: 999.99, category: 'Electronics', active: true
      });
      this.up('form').getForm().loadRecord(record);
    }
  }, {
    text: 'Save',
    handler: function() {
      var form = this.up('form').getForm();
      var record = form.getRecord() || Ext.create('MyApp.model.Product');
      form.updateRecord(record);
      console.log(record.getData());
    }
  }]
});

Expected output: Clicking Load populates the form fields from the model record. Clicking Save writes form values back to the model and logs the data object.

Dynamic Form Manipulation

var form = Ext.create('Ext.form.Panel', {
  title: 'Dynamic Form',
  bodyPadding: 15,
  items: [{
    xtype: 'combobox',
    fieldLabel: 'Type',
    name: 'type',
    store: ['Personal', 'Business'],
    listeners: {
      change: function(combo, newValue) {
        var form = combo.up('form');
        var field = form.down('[name=companyName]');
        if (newValue === 'Business') {
          field.show();
          field.allowBlank = false;
        } else {
          field.hide();
          field.allowBlank = true;
        }
        form.updateLayout();
      }
    }
  }, {
    xtype: 'textfield',
    fieldLabel: 'Company Name',
    name: 'companyName',
    hidden: true
  }]
});

Expected output: Selecting "Business" in the Type combo reveals the Company Name field and makes it required. Selecting "Personal" hides it again.

Common Mistakes

  1. Not calling form.isValid() before submit - Always validate the form first. Submit will still send, but the server will reject invalid data.

  2. Confusing form.submit() and form.updateRecord() - submit() sends data via Ajax to the server. updateRecord() writes form values to an Ext JS Model without a server request.

  3. Forgetting to set name property - Field values are keyed by name when getting values, submitting, or binding to a model. Without name, the value is not accessible.

  4. Not handling form destruction - When removing a form panel, call form.destroy() to clean up field listeners and prevent memory leaks in long-lived applications.

  5. Overriding field values without validation - Calling setValue() programmatically bypasses the field's validation. Use setValue() with the raw parameter set to true or manually call field.validate() after.

Practice Questions

  1. How do you check if all fields in a form are valid?
  2. What is the difference between vtype and a custom validator function?
  3. How do you load form data from an existing Model record?
  4. What happens when you call form.submit() without setting the url property?
  5. How do you dynamically show and hide fields based on user input?

Challenge: Build a product registration form with conditional fields (different fields for physical vs digital products), cross-field validation (end date must be after start date), combo boxes with remote Stores, and a grid showing already-submitted products below the form.

FAQ

What is the difference between form.submit() and standard Ajax requests?

form.submit() automatically serializes all field values, handles validation, and fires success/failure callbacks with the server response. Manual Ajax requires building the parameter object yourself.

How do I populate a ComboBox from a remote source?

Set the store's proxy to ajax with the API URL. The ComboBox queries the server as the user types when queryMode is 'remote'.

Can I reuse the same field configuration across multiple forms?

Yes. Define fields as a shared Ext JS class or use a field container xtype. You can also clone field config objects with Ext.apply({}, baseConfig).

How do I handle file uploads in Ext JS forms?

Set the form's fileUpload to true and include a filefield component. The form uses a hidden iframe to submit the file without page refresh.

What is the difference between anchor, hbox, and vbox form layouts?

Anchor stretches fields relative to the form width. Hbox arranges fields horizontally. Vbox stacks them vertically. Mix layouts with nested containers for complex forms.

Mini Project

Build a customer registration form with: text fields for name, email, phone, and address; combo box for country with remote loading; date field for date of birth; radio group for gender; checkbox group for notification preferences; a grid showing registered customers below; and full create/update/delete with server sync via a shared Store.

What's Next

Forms collect data. Learn how Ext JS Tree Panels display hierarchical data with expandable nodes, drag-and-drop, and Lazy Loading.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro