Skip to content

Form validation

Quiet form controls are form-associated custom elements , meaning their values will submit just like native form controls when you give them a name.

To align with the platform, validation is built on top of the Constraint Validation API . This allows Quiet's form controls to work seamlessly with native form validation techniques. You can use most standard HTML validation attributes and access validation states and methods in the same way as native form controls.

Basic validation Jump to heading

The simplest way to validate a form control is with HTML validation attributes. For example, you can make a text field required by adding the required attribute.

Submit
<form action="about:blank" target="_blank">
  <quiet-text-field
    name="username"
    label="Username"
    required
    style="margin-block-end: 1rem;"
  ></quiet-text-field>
  <quiet-button type="submit">Submit</quiet-button>
</form>

Each component defines its own validation attributes, but the most common ones include:

  • required - Makes the field required
  • pattern - Validates against a regular expression
  • minlength + maxlength - Sets minimum and maximum length requirements
  • min + max - Sets minimum and maximum value requirements
  • step - Controls value increments
  • type - Validates against a specific input type (e.g. email, url, number)

Refer to each component's documentation for a complete list of supported attributes.

Custom validation messages Jump to heading

While browsers provide default validation messages, you can customize them using the setCustomValidity() method, just like native form controls.

Submit
<form action="about:blank" target="_blank">

  <quiet-text-field
    id="password"
    name="password"
    label="Password"
    required
    minlength="8"
    style="margin-block-end: 1rem;"
  ></quiet-text-field>

  <quiet-button type="submit">Submit</quiet-button>
</form>

<script type="module">
  const password = document.querySelector('#password');

  await customElements.whenDefined('quiet-text-field');

  password.setCustomValidity('The cats will not be happy until your password is at least 8 characters');
</script>

Remember to clear the custom validity message by calling setCustomValidity('') when the input becomes valid, otherwise the field will remain invalid and won't allow the form to submit.

Validation states Jump to heading

Form controls have various states that reflect their validation status. You can use these states for styling or to provide feedback to users.

<quiet-text-field
  id="email"
  name="email"
  label="Email"
  type="email"
  required
></quiet-text-field>

<script>
  const email = document.querySelector('#email');

  // Check if the field is valid
  console.log(email.validity.valid);

  // Check specific validation states
  console.log(email.validity.valueMissing); // is required but empty
  console.log(email.validity.typeMismatch); // doesn't match type="email"
</script>

Validation states are updated automatically as the user interacts with the form control. You can also trigger validation programmatically using the reportValidity() method. To check validity without showing the browser's error message, checkValidity() instead.

Styling validation Jump to heading

Quiet form controls expose custom states you can target with CSS. These states make it easy to style controls based on their current state.

Submit Reset
<form action="about:blank" target="_blank" id="example__styling">
  <quiet-text-field
    name="email"
    label="Email"
    type="email"
    placeholder="Enter a value and blur the field"
    required
    id="example__styling"
  ></quiet-text-field>
  <quiet-button type="submit">Submit</quiet-button>
  <quiet-button type="reset">Reset</quiet-button>
</form>

<style>
  #example__styling {
    quiet-text-field:state(user-valid) {
      outline: solid 2px var(--quiet-constructive-stroke-mid);
      outline-offset: .5rem;
    }

    quiet-text-field:state(user-invalid) {
      outline: solid 2px var(--quiet-destructive-stroke-mid);
      outline-offset: .5rem;
    }

    quiet-text-field {
      margin-block-end: 1rem;
    }
  }
</style>

The following pseudo-classes are available to style all form controls.

  • :valid - Applied immediately and always when the control is valid.
  • :invalid - Applied immediately and always when the control is invalid.

You can also use various custom states, which must be wrapped in the :state() selector. Here are some examples, but remember that not all components implement all of these states, so please refer to the respective component's documentation.

  • :state(disabled) - Applied when the control is disabled
  • :state(blank) - Applied when the control has a blank value
  • :state(focused) - Applied when the control has focus
  • :state(user-valid) - Applied when the control is valid and the user has interacted with it
  • :state(user-invalid) - Applied when the control is invalid and the user has interacted with it

The user-valid and user-invalid states are only applied after user interaction to prevent premature validation feedback.

Validating entire forms Jump to heading

To validate an entire form, you can use the form's checkValidity() method. This will trigger validation on all form controls within the form, including Quiet and native elements.

Sign up
<form action="about:blank" target="_blank" id="signup-form">
  <quiet-text-field
    name="username"
    label="Username"
    required
    style="margin-block-end: 1rem;"
  ></quiet-text-field>

  <quiet-text-field
    name="email"
    label="Email"
    type="email"
    required
    style="margin-block-end: 1rem;"
  ></quiet-text-field>

  <quiet-button type="submit">
    Sign up
  </quiet-button>
</form>

<script>
  const form = document.querySelector('#signup-form');

  form.addEventListener('submit', event => {
    if (!form.checkValidity()) {
      event.preventDefault();
    }
  });
</script>
Search this website Toggle dark mode Get the code on GitHub Follow @quietui.org on Bluesky Follow @quiet_ui on X
    No results found