Validate on the server as the user types — no client validation library. The form's
Change action re-checks the fields and the template renders each error next to its
input via {{.lvt.AriaInvalid}} + {{.lvt.ErrorTag}}. Submit is only accepted once
ctx.ValidateForm() passes.
The browser enforces HTML rules (type="email", required, minlength); the server
re-checks the same rules and renders aria-invalid + the error message inline.
{{define "content"}}
<article>
<h3>Inline Validation</h3>
<form method="POST">
<fieldset>
<label>Email
<input type="email" name="email" value="{{.Email}}" required {{.lvt.AriaInvalid "email"}}>
{{.lvt.ErrorTag "email"}}
</label>
<label>Username
<input name="username" value="{{.Username}}" required minlength="3" maxlength="20" {{.lvt.AriaInvalid "username"}}>
{{.lvt.ErrorTag "username"}}
</label>
<button type="submit">Submit</button>
</fieldset>
</form>
{{if .Saved}}<ins style="display:block;text-decoration:none">Saved successfully!</ins>{{end}}
</article>
{{end}}
Change updates the touched field and runs ValidateForm (errors surface via the
template tags); Submit rejects until validation passes.
type InlineValidationController struct{}
func (c *InlineValidationController) Change(state InlineValidationState, ctx *livetemplate.Context) (InlineValidationState, error) {
if ctx.Has("email") {
state.Email = ctx.GetString("email")
}
if ctx.Has("username") {
state.Username = ctx.GetString("username")
}
_ = ctx.ValidateForm()
return state, nil
}
func (c *InlineValidationController) Submit(state InlineValidationState, ctx *livetemplate.Context) (InlineValidationState, error) {
if err := ctx.ValidateForm(); err != nil {
return state, err
}
state.Saved = true
return state, nil
}
func inlineValidationHandler() http.Handler {
tmpl := newLayoutTmpl("templates/layout.tmpl", "templates/forms/inline-validation.tmpl")
return tmpl.Handle(&InlineValidationController{}, livetemplate.AsState(&InlineValidationState{
Title: "Inline Validation",
Category: "Forms & Editing",
}))
}
type InlineValidationState struct {
Title string
Category string
Email string
Username string
Saved bool
}