Skip to content

Triggering native validation messages with JavaScript

If input constraints are declared on a field, it might display as invalid immediately.
This is not a good user experience. Usually an invalid state message is only displayed when a form is submitted or after a user interacts with a form input.

One way to implement this is by adding the constraint attributes with JavaScript at the appropriate time.

Applying constraints on submit

The example below checks validity when the form is submitted. Note one of the fields is not always rendered.

<script>
    function initMyForm() {
        return {
            validate(event) {
                // add required attribute
                this.$refs.amount.required = true;
                this.$refs.currency && (this.$refs.currency.required = true);

                // show native browser error message if any constraints are violated
                this.$refs.amount.form.reportValidity();

                // prevent submitting the form if any field is invalid
                if (!this.$refs.amount.form.checkValidity()) {
                    event.preventDefault();
                }
            }
        }
    }
</script>
<form x-data="initMyForm()" action="" method="post"
      @submit="validate($event)"
>
    <input type="number"
           name="amount"
           x-ref="amount"
           class="form-input p-2 invalid:ring-2 invalid:ring-red-500"
    />
    <?php if ($block->isCurrencyChooserEnabled()): ?>
    <select name="currency"
            x-ref="currency"
            class="form-select mb-4 invalid:ring-2 invalid:ring-red-500"
    >
        <?= $escaper->escapeHtml(__('Choose an Amount...')) ?>
        <?php /** @noEscape */ $block->getCurrencyChooserOptionsHtml(); ?>
        <?php endif; ?>
    </select>
</form>

Applying constraints on user interaction

Note that in this example an empty value would still be considered as valid since the required attribute will not be present in that case.

<input name="amount"
       x-ref="amount"
       :required="$refs.amount.value.length > 0"
       class="form-input p-2 invalid:ring-2 invalid:ring-red-500"
/>

Alternatively event subscribers for @input or @focus can be used to toggle constraint attributes.

<input name="amount"
       @input="$event.target.min='3'"
       class="form-input p-2 invalid:ring-2 invalid:ring-red-500"
/>

Custom error messages

In case the native browser messages and constraints are not sufficient, an input field can be marked as invalid by calling setCustomValidity(msg) on it. To mark a field as valid again, call setCustomValidity('') with an empty string.

<script>
    function initMyForm() {
        return {
            validateField() {
                // some code calculating the value of m ...
                return m > 0
                    ? `You have to wait ${m} minutes before you can continue.`
                    : '';
            }
        }
    }

</script>
<input name="amount"
       @input="$event.target.setCustomValidity(validateField())"
       class="form-input p-2 invalid:ring-2 invalid:ring-red-500"
/>