errors, isTouched, validation) and depend on no validation library — there is no felte or zod in the
package. Bring whatever you like: a schema library, server-side errors, or a few lines of
hand-rolled logic.The tests below use Felte + Zod as one convenient, type-safe example — it eliminates boilerplate, and its errors / touched output maps straight onto the errors / isTouched props these components
expect. But it's entirely optional. Jump to the Bring Your Own Validation section at the bottom to see the exact same components
driven by a plain function, with no library at all.
Felte Setup
1. Install Dependencies
2. Create Form with Schema
3. Use in Template
Common Zod Patterns
Interactive Tests
Each form in this section uses Felte with Zod validation. (For the no-library version, see Bring Your Own Validation below.)
Test 1: Basic Email Validation
Test 2: Multiple Fields Validation
Test 3: Touched Behavior
Both inputs have the same error, but only the touched one shows error styling.
This demonstrates how isTouched controls error visibility.
Test 4: Select & Date Validation
Test 5: Password with Cross-Field Validation
Password requires: 8+ characters, uppercase letter, and a number. Uses Zod's .refine() for cross-field validation.
Real Use Case: Create User Form
admin@example.com to see a server-side validation error.Test 6: Manual State Override
The validation prop takes precedence over the state auto-derived from errors.
This is useful when you need manual control.
Test 7: Accessibility (aria-invalid)
Open browser DevTools and inspect these inputs to verify aria-invalid attribute.
Bring Your Own Validation
errors / isTouched / validation props, so a
plain function and a little $state is all you need. Swap in your own rules, a
different schema library, or server-side errors exactly the same way.Hand-rolled validation with FormField
Type an email. Validation runs on every keystroke via a plain $derived function and
feeds its result straight into FormField's errors prop — the very same
prop Felte would populate. Nothing else is different.
The validation
The template
Even lower level — FormGroup + FormHelp, no FormField
You don't even need FormField. Drop to FormGroup, FormHelp and Input and set the validation and message
yourself. Type at least 8 characters to see it flip to success.