Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Validation in the Form: Client-Side and Server-Side

Validation in the Form: Client-Side and Server-Side

~7 Min. Lesezeit Zuletzt aktualisiert am August 9, 2026

A UI Components form only validates in the browser by default - that's a convenience for the editor, but not a security mechanism. Forgetting server-side validation in the save controller opens the door to empty required fields or tampered requests.

Client-side validation, declaratively

Validation rules are declared via validation directly on the relevant field definition - no custom JavaScript line needed:

<field name="title" formElement="input">
    <settings>
        <dataType>text</dataType>
        <label translate="true">Title</label>
        <validation>
            <rule name="required-entry" xsi:type="boolean">true</rule>
            <rule name="max_text_length" xsi:type="number">255</rule>
        </validation>
    </settings>
</field>

The available rule names (required-entry, validate-email, validate-number, max_text_length, min_text_length, validate-url, ...) come from Magento's own jQuery validation rule set, which UI Components uses under the hood - the same rule names you'd also know from classic Luma forms.

Marking required fields visually

required-entry automatically enables both the JS validation and the red asterisk next to the label - no separate attribute is needed for that.

Server-side validation in the save controller

The actual safeguard happens server-side, in the save controller (chapter 12 shows the full controller) - here's an excerpt of the validation itself:

/**
 * Validates the posted announcement data.
 *
 * @param array<string, mixed> $data Raw POST data.
 * @return void
 * @throws LocalizedException
 */
private function validate(array $data): void
{
    if (trim((string) ($data['title'] ?? '')) === '') {
        throw new LocalizedException(__('Title is required.'));
    }

    if (mb_strlen((string) $data['title']) > 255) {
        throw new LocalizedException(__('Title must not exceed 255 characters.'));
    }

    if (trim((string) ($data['message'] ?? '')) === '') {
        throw new LocalizedException(__('Message is required.'));
    }
}

Achtung: assert() is forbidden for validation logic in this project - in production mode, assert() can be silently disabled depending on the zend.assertions setting, which would drop the check entirely without the failure ever becoming visible. Explicit if checks with LocalizedException belong in the controller instead, as shown above.

Showing errors to the user

If the save controller catches the LocalizedException, the error message is shown via $this->messageManager->addErrorMessage(), and the last entered values stay in the form through DataPersistorInterface - chapter 12 shows this full flow inside the save controller.

Tipp: Client- and server-side validation should express the same rules, but they're deliberately two separate implementations: one is about good usability (instant feedback without a page reload), the other about actual data integrity. Skipping one because the other "already checks it" is a common but avoidable mistake.