forms · primitive
Inline validation
Live validation patterns — masked inputs, character counters, async availability checks. These compose plain
UInput + a Vue ref + a small handler. No new component to ship; the patterns are the shipped primitive. live counter
Character remaining
238 characters remaining
masked input
Phone number
Type digits; mask formats automatically.
LET-NUM format, e.g. GM-123456.
Bound: phone=(empty) · grantId=(empty)
async availability
"This email is taken"
Try "taken@example.org" to see the conflict state.
notes
Why no Tux wrapper
Each of these is ten lines of Vue. Wrapping them in a single component would obscure intent and lock the host app into one masking convention. The patterns here transfer cleanly to any consumer (Landscape admin, tti-ai-studio settings, sponsor-portal forms) — copy the handler, point it at the right ref.