Form Validation
View OriginalServer-side field validation with HTMX. Fields validate on change, dependent fields update automatically (e.g. slug from name), and full-form submit validates everything at once.
Goshtoso Component
Go + TemplTry it out
Type in the fields below and tab out to see validation in action. The slug field auto-generates from name. Try "admin", "test", or "demo" as slugs to see the uniqueness check.
Usage Example
// 1. Define the form fields and validation rules
def := &validation.FormDef{
FormID: "demo-validation",
Endpoint: "/api/components/form-validation",
Fields: map[string]*validation.FieldDef{
"name": {Name: "name", FieldGroup: nameField, OnChange: true},
"slug": {Name: "slug", FieldGroup: slugField, OnChange: true, DependsOn: []string{"name"}},
"email": {Name: "email", FieldGroup: emailField, OnChange: true},
},
}
def.Bind() // wires up HTMX attributes and metadata
// 2. In the templ, render the form with FieldGroups
@form.Form(form.Config{
ID: "demo-validation",
HTMX: &form.HTMXConfig{Post: "/api/components/form-validation", Target: "#form-result", Swap: "innerHTML"},
Footer: &form.FooterConfig{SubmitText: "Submit", CancelText: "Reset"},
}) {
@form.Section(form.SectionConfig{Title: "Project Details"}) {
@form.FieldGroup(*nameField)
@form.FieldGroup(*slugField)
@form.FieldGroup(*emailField)
}
}
// 3. Handle validation in Go
func (s *Server) handleFormValidation(w http.ResponseWriter, r *http.Request) {
def := buildDemoFormDef()
result := validation.Handle(r, def, validateDemoField)
if validation.IsFieldValidation(r) {
validation.RenderFieldResponse(r.Context(), w, *result)
return
}
// full submit...
}
// 4. Per-field validation hook
func validateDemoField(ctx validation.ValidationContext, name string, fg *form.FieldGroupConfig) bool {
switch name {
case "name":
val := ctx.FormValues["name"]
if len(val) < 3 {
fg.Errors = []string{"Name must be at least 3 characters."}
fg.Input.State = textinput.StateError
return false
}
fg.Input.State = textinput.StateSuccess
return true
case "slug":
// auto-generate from name on dependency trigger
if ctx.Type == validation.ValidationDependency && val == "" { ... }
// uniqueness check against takenSlugs map
case "email":
// format validation
}
}