Back to top

Form Validation to Dynamic UIs: The JavaScript forms Handbook

Published: Jan 1, 2024


Forms are the backbone of user interaction on websites and web applications. Normally when a user registers for an account, checks out on an e-commerce store, fills out a contact form, or interacts with a web app, they are working with HTML forms.


Some examples of common forms include:

  • User registration and login forms
  • Contact forms
  • Shopping cart checkout forms
  • Survey and poll forms
  • Search forms
  • And countless custom forms for web apps

With JavaScript, we can customize and enhance these form experiences in all kinds of powerful ways: ✅ Real-time form validation for providing feedback ✅ Dynamically updating forms as the user types ✅ Improving overall usability and user experience


The key is tapping into form events triggered by user interactions. Let’s explore the most essential events to be aware of when coding forms with JavaScript.


Events Inside Forms


All HTML form elements have special events that are triggered when users interact with them. Being able to listen for these events is the foundation for handling form submissions and providing a great experience.


Here are some of the most common form events you’ll work with:


Submit Event


Here is how you can listen for the submit event:


// Get form reference
const form = document.querySelector('form');

// Listen for submit 
form.addEventListener('submit', function(e) {
// Form submit logic
});

Now code can be executed each time a submit occurs, before the data is actually sent to the server.


Change Event


Inputs like text fields, select dropdowns, and checkboxes all trigger a “change” event when their value changes. For example:


<input type="text" id="username">

const username = document.querySelector('#username');

username.addEventListener('change', function(e) {
    // Runs whenever the value changes
}); 

Input Event


Very similar to the change event, but input elements also fire this one on every keystroke. This enables handling logic in real-time as the user types.


Reset Event


Fires when a reset button is clicked, allowing you to clear or reset form values using JavaScript.


And more form elements have additional events as well like click, focus, blur, and more. We can handle all user interactions inside forms through events!


Submit Events


The submit event is one of the most important events in form handling. It fires whenever a user attempts to submit a form.


This includes:

  • Clicking a button with type="submit"
  • Pressing Enter in a text input field
  • Submitting the form through JavaScript code

Some key things we can do on submit:

  • Validate form data before sending it
  • Modify form values on the fly
  • Prevent the default submission behavior
  • Display a “Submitting…” message

Here’s an example submit handler:


form.addEventListener('submit', function(e) {
    // Validate form
    // If valid, show loading spinner
    e.preventDefault(); // Prevent default submit
    // Collect data  
    // Make AJAX request to submit data
});

The default behavior reloads the page after a form submits. We often want more control and to send the data asynchronously instead.


Stopping the default action with event.preventDefault() gives us more flexibility to handle submissions as we please.


Regular Expressions


Regular expressions (or “RegEx”) are pattern matching tools built into JavaScript. They give us an extremely flexible way to: ✅ Validate text formats like emails, phone numbers and more ✅ Replace matched text through search/replace ✅ Extract parts of a string


For example, this regular expression checks if a string is a valid email address:


const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/;

// Use it like:
if (emailRegex.test(someEmail)) {
    // Valid email format
}

The patterns look complicated at first glance, but after some practice they become intuitive!


RegEx is perfect for:

  • Form validation
  • Making robust input sanitizers
  • Improving search algorithms

Testing RegEx Patterns


When first learning regular expressions, testing and debugging patterns is crucial before relying on them. There are a few handy online tools that make RegEx testing easy:


RegExr


RegExr allows you to visualize your expressions by highlighting matches in test strings.


It also explains each part of your pattern in plain English, which is super helpful for breaking it down.


RegEx 101


RegEx 101 is another great playground with various modes like explainers, cheat sheets, and support for different code languages.


These online regex testers are indispensable when debugging a complex validation pattern or learning the syntax.


Unit Testing


For validation functions in your projects, unit test them against various valid and invalid input values:


test('validates phone numbers', () => {
    // True 
    expect(validatePhone('201-555-0134')).toBe(true);  
    // False
    expect(validatePhone('hello world')).toBe(false);
});

Basic Form Validation


Now that we know how to listen for form events and leverage RegEx for matching patterns let’s put them together for form validation.


Here is a simple example with a registration form:


// Get form and inputs
const form = document.querySelector('#register-form');
const emailInput = document.querySelector('#email');

// Valid email pattern   
const emailRegex = //...

// Listen for submit 
form.addEventListener('submit', e => {
    // Validate email
    if (emailRegex.test(emailInput.value)) {  
      // Valid email
    } else {
      // Show error
      e.preventDefault(); // Prevent submit
    }
});

We can have as many validations as needed for each input before allowing the form submission. Key principles: ✅ Prevent the default action on invalid
✅ Display clear error messages
✅ Use good UX design


Keyboard Events


In addition to element-specific events like “change” and “submit”, we can also listen for keyboard presses.


Some common keyboard events:

  • keydown - User presses a key
  • keyup - User releases a key
  • keypress - After a full keypress

Here’s an example giving visual feedback as the user types into a text field:


const input = document.querySelector('input');

// Listen for keyup
input.addEventListener('keyup', function(e) {
    // Check if key is alphanumeric
    if (e.keyCode >= 48 && e.keyCode <= 90) {  
      // Show icon for valid alphanumeric key
      showValidIcon();
    } else {
      // Invalid key, user should fix
      showInvalidWarning();
    }
});

We get the pressed key code from event.keyCode. Useful for validation, interactions, mobile optimization, and more!


Advanced Form Interactions


With a solid grasp on form events and validation, let’s explore some advanced UI interactions to enhance the user experience.


Conditional Logic


We can use JavaScript to conditionally show or hide certain inputs based on previous selections.


For example, toggle additional address fields if a “See my billing address” checkbox is unchecked in checkout. Minimize cognitive load for users by only showing what’s relevant at the moment.


Dynamic Updates


Make forms feel responsive by dynamically updating values or full sections based on input. A few ideas:

  • Update form field placeholders based on context
  • Show password strength meters as user types
  • Pre-fill suggested values from a database
  • Add or remove options from selects

This creates a smooth, app-like experience while retaining ease of use.


Form Steppers


Guide users through multi-step forms while breaking down complex processes. Track step progress, move forward/backward as needed, and persist data across sessions.


Advanced form UX principles paired with JavaScript events opens the door for all kinds of possibilities to improve the user experience!


Accessibility Considerations


When building forms, we must ensure they are usable and accessible for all users. Some key areas to focus on:


Semantic Structure


Use proper HTML form element tags like <form>, <input>, <select>, and associated ARIA roles. Screen readers announce them appropriately so users understand it’s a form.


Labels


Every input must have an associated <label>. It links them programmatically for screen readers and allows clicking the labels to focus the inputs.


Keyboard Navigation


Test only using keyboard - no mouse. All form controls should receive focus as expected. Submit on Enter press, escape closes modals, etc.


Color Contrast


Inputs and error text must meet minimum color contrast ratios so visually impaired users can read them.


Error Messaging


On validation errors, include descriptive error messages associated with inputs. Explain exactly what needs fixing rather than generic alerts.


Form Security


When dealing with sensitive user data, security is paramount. JavaScript introduces some key web vulnerabilities to be aware of when coding forms.


Cross-Site Scripting (XSS)


XSS attacks inject malicious client-side code. Common if you display input data without sanitizing it first.


For example displaying a comment or username straight from POST data. Encode special chars or strip dangerous tags like <script> from data.


Cross-Site Request Forgery (CSRF)


CSRF tricks users into unknowingly submitting a forged request appearing to come from your site. Protect against it by adding security tokens.


These are just a few basics - security deserves its own thorough discussion! The key is rigorously validating, sanitizing, and encoding all form data server-side before doing anything sensitive with it.


Security ConcernDescriptionPotential Solutions
Cross-Site Scripting (XSS)
Injecting client-side scripts into web apps through insufficiently validated user input that could be displayed and executed in victims' browsers
- Validate and sanitize all user input before displaying
- Encode special characters on output
- Implement CSP policies restricting sources
Cross-Site Request Forgery (CSRF)
Tricking users into unknowingly submitting unauthorized commands
- Add CSRF tokens to forms
- Validate SameSite cookie protections
- Require re-authentication for sensitive operations
Insecure Direct Object References
Gaining unauthorized access to data by manipulating ID parameters predicting other records
- Indirect reference maps
- Permissions checks on server backend
SQL Injection
Inserting malicious SQL into input fields to gain access or corrupt/delete data
- Parameterized queries
- Input validation
- Least privilege DB permissions
HttpOnly Cookie Theft
Stealing session cookies via XSS to impersonate users
- Set cookie HttpOnly flag
- Regenerate session on privilege change
Password Brute Forcing
Guessing weak login passwords through automatic rapid attempts
- Password complexity rules
- Account lockouts
- Multi-factor authentication


This visual association of risks and solutions helps quickly identify and mitigate common attack vectors when building secure forms. OWASP is one great resource for more in-depth web security guidance.


Best Practices


When working with JavaScript-powered forms, keep these high-level best practices in mind:


Validate Early, Validate Often


The earlier invalid data can be caught, the better the user experience. Validate on the client side and again on the server. Provide helpful validation messages tailored to each input.


Practice Progressive Enhancement


Forms should function properly without JavaScript. Progressive enhancement means gracefully adding JavaScript to augment default form flows rather than fully overriding them.


Structure for Simplicity


Break bigger forms into composable sections grouped by context. Manage state in a single source of truth object. Structure data for easy serialization/submission.


User Experience Comes First


At every stage, consider the user’s perspective. Is this input clear? Does this validation message help guide to the solution? Remove friction through thoughtful interactions.


Plan for Extensibility


Requirements change over time. Build reusable frameworks for form generation based on configuration. Decouple dependencies to simplify maintenance as forms grow.


Following best practices leads to pleasant, productive form experiences for both users and developers long-term.


Conclusion


We’ve explored many of the fundamentals around working with JavaScript forms and form events - but this only scratches the surface of possibilities.


As a next step, practice building UI interactions leveraging techniques we’ve covered like conditional logic or toggling visibility. See implementing form validation in a real production signup flow.


From there, you could dive deeper into individual topics like:

  • Form accessibility practices
  • Creative custom input components
  • Security hardening forms
  • Optimizing performance
  • And much more!

Learning forms is like learning the grammar of a language. Master forms in JavaScript, and you can give users delightful, responsive experiences on the modern web.