Skip to content

Server-Side Errors

Handle validation errors returned from an API. Use setError() to display server errors on specific fields, clearErrors() to dismiss them, and getErrors() to read the current error state.

What this example covers:

  • Setting server-side errors with form.setError(field, message)
  • Clearing errors with form.clearErrors()
  • Reading all errors with form.getErrors()
  • Showing a loading state with getFormState().isSubmitting

Live Demo

JavaScript

The handleSubmit callback simulates an API call. If the server returns an error, setError() attaches it to the relevant field. The form's isSubmitting state is managed automatically during async submissions.

js
Alpine.data('serverErrorsForm', () => ({
    result: '',
    showResult: false,
    form: Alpine.Form(
        { email: '', username: '' },
        {
            config: {
                validationMode: 'onTouched',
                validations: {
                    email(value) {
                        if (!value) return { message: 'Email is required' };
                    },
                    username(value) {
                        if (!value) return { message: 'Username is required' };
                    },
                },
            },
        },
    ),
    async handleSubmit(data) {
        // Simulate a server response with errors
        await new Promise((r) => setTimeout(r, 800));
        const raw = Alpine.raw(data);
        if (raw.email === 'taken@example.com') {
            this.form.setError('email', 'This email is already registered');
            return;
        }
        if (raw.username === 'admin') {
            this.form.setError('username', 'This username is not available');
            return;
        }
        this.showResult = true;
        this.result = 'Registration successful!\n' + JSON.stringify(Alpine.raw(data), null, 2);
    },
}));

HTML

The submit button is disabled while the form is submitting, and its label changes to show a loading state. The state bar shows live error and submission state.

html
<p style="color: #64748b; font-size: 14px; margin-top: 0">
    Try email <code>taken@example.com</code> or username <code>admin</code> to trigger server
    errors.
</p>

<div x-data="serverErrorsForm">
    <form @submit.prevent="form.submit(handleSubmit)">
        <div class="field-group">
            <label>Email</label>
            <input
                x-register:form="form.field('email')"
                type="email"
                placeholder="Try: taken@example.com"
            />
            <span
                class="field-error"
                x-show="!form.getFieldState('email').isValid"
                x-text="form.getFieldState('email').error"
            ></span>
        </div>
        <div class="field-group">
            <label>Username</label>
            <input x-register:form="form.field('username')" type="text" placeholder="Try: admin" />
            <span
                class="field-error"
                x-show="!form.getFieldState('username').isValid"
                x-text="form.getFieldState('username').error"
            ></span>
        </div>
        <div class="btn-group">
            <button type="submit" :disabled="form.getFormState().isSubmitting">
                <span
                    x-text="form.getFormState().isSubmitting ? 'Registering...' : 'Register'"
                ></span>
            </button>
            <button type="button" @click="form.clearErrors()">Clear Errors</button>
            <button type="button" @click="form.reset()">Reset</button>
        </div>
    </form>
    <pre x-show="showResult" x-text="result"></pre>
    <div class="state-bar">
        <span>Valid: <strong x-text="form.getFormState().isValid"></strong></span>
        <span>Submitting: <strong x-text="form.getFormState().isSubmitting"></strong></span>
        <span>Errors: <strong x-text="JSON.stringify(form.getErrors())"></strong></span>
    </div>
</div>

API Reference

js
form.setError('email', 'Already taken'); // Set error on a field
form.clearErrors('email'); // Clear one field
form.clearErrors(); // Clear all
form.getErrors(); // { email: 'Already taken' }

Released under the MIT License.