This demo shows how native HTML5 constraint validation (min, max,
pattern, type, required) works in sync with Fore's update cycle.
The browser's ValidityState is read (side-effect-free) at the end of
fx-model.revalidate() and propagated via ModelItem.nativeValid
into AbstractControl.handleValid().
checkValidity() fires events:
The integration reads widget.validity.valid (a live property) rather than calling
widget.checkValidity(). Calling checkValidity() dispatches an
invalid event on the input that would clash with Fore's own invalid
event on fx-control.
:invalid flash on page load:
CSS :valid and :invalid apply the moment the page renders — before
the user touches anything. The solution is :user-valid / :user-invalid,
which wait for interaction. For browsers that don't support them yet, the
:valid:not(:placeholder-shown) / :invalid:not(:placeholder-shown)
fallback produces the same behaviour. Both patterns are integrated in fore.css.
required
Both fx-bind required="true()" and native
required on the input are set. Either alone would mark
the field invalid.
required only, no fx-bind required
No required facet is declared for this field at all —
only the native required attribute written directly on the
input.
type="number" min="0" max="120"
Native range validation via validity.rangeUnderflow /
validity.rangeOverflow. No XPath constraint needed.
type="email"
Native email format check via validity.typeMismatch.
Combined with XForms required.
pattern="[0-9][0-9][0-9][0-9][0-9]" (5 digits)
Native pattern check via validity.patternMismatch.
Empty input is valid here (not required) — only non-empty invalid patterns fail.
minlength="3" maxlength="20"
Length validation via validity.tooShort /
validity.tooLong. Browsers block typing beyond
maxlength, so tooLong is only reachable by
programmatic value assignment. Empty input is valid (not required).
type="number" min="0.01" step="0.01"
Validates positive currency amounts. validity.stepMismatch
catches values that don't align to the step (e.g. three decimal places).