title: "Step 8 — Forms & Validation" active_step: 8

# Step 8 — Forms & Validation

Server-side and client-side validation declared in HTML. No JavaScript required.

## How validation works

Add `w-validate` to any `<form>`. Annotate fields with validation attributes. wwwhat validates server-side on submit and also injects client-side validation without any JavaScript from you.

    <form method="post" action="/w-action/contacts" w-validate>
      <input name="email" type="email" w-required>
      <input name="age" type="number" w-min="18" w-max="99">
      <button type="submit">Save</button>
      <button type="reset">Cancel</button>
    </form>

    <!-- CSRF token is auto-injected. No manual setup needed. -->

## Live example — contact form

#flash.success#
#flash.error#
Full name *
#errors.name#
Email address *
#errors.email#
Message * #old.message#
#errors.message#
Minimum 10 characters

## Validation attributes

Attribute | Effect
--- | ---
`w-required` | Field must not be empty
`w-min="N"` | Min length (text) or min value (number)
`w-max="N"` | Max length (text) or max value (number)
`type="email"` | Valid email format enforced

## Error display and value preservation

On validation failure, `#errors.field#` contains the error message. `#old.field#` contains the previously submitted value so the user doesn't have to retype everything.

    <input name="email" value="#old.email#" w-required>
    <if errors.email>
      <div class="error">#errors.email#</div>
    </if>

## Flash messages

After a form submit, flash messages are set by the engine and consumed once on the next render. Use them to show success or error notices.

    <if flash.success>
      <div class="alert alert-success">#flash.success#</div>
    </if>

    <if flash.error>
      <div class="alert alert-danger">#flash.error#</div>
    </if>

What you learned

- `w-validate` on a form enables validation (both server + client-side)
- Validation attrs: `w-required`, `w-min="N"`, `w-max="N"`
- `#errors.fieldname#` contains the error message for that field
- `#old.fieldname#` repopulates the field after a failed submit
- `#flash.success#` and `#flash.error#` for one-time messages
- CSRF tokens are auto-injected — every POST form is protected against forgery
- Always include a `<button type="reset">` to let users cancel