Validation

# Client-side validation

validate: true mirrors your ActiveModel validators into shipped Stimulus controllers — the no-phlex-reactive fallback.

## Turning it on

`validate: true` introspects the model's validators and emits `data-validations--*` bindings per field, plus a form-level submit coordinator. The form gets `novalidate` — the shipped Stimulus controllers own error display, so you never see the inconsistent native browser bubbles.

```ruby
Form(model: @partner, validate: true) do |f|
  f.field :title
  f.field :note
  f.submit :primary
end
```

Register the controllers once (see [Installation](https://phlex-forms.zoolutions.llc/docs/installation)):

```javascript
import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
lazyLoadControllersFrom("phlex_forms/controllers", application)
```

## Per-field overrides

```ruby
Form(model: @partner, validate: true) do |f|
  f.field :title                                      # every validator on :title
  f.field :slug, validate: false                      # opt this field out
  f.field :note, validate: { length: { maximum: 30 } } # explicit inline rules
end
```

## What's supported

Presence, length (with a live character counter), format, numericality, inclusion, exclusion, confirmation, and acceptance.

Validators with `:if`, `:unless`, or `:on` are **skipped** — they need server context — and uniqueness can't be checked client-side. The server stays authoritative either way; this layer is UX, not enforcement.

> **Tip:** If those gaps matter, [live validation](https://phlex-forms.zoolutions.llc/docs/live-validation) closes all of them by running the real validators server-side.

## Messages & i18n

Validation messages ship for `en`, `fr`, and `af`; override any string client-side via `window.PhlexForms.messages`. The engine prepends the gem's locale files to `I18n.load_path`, so your app's files win.