Form validation (JS)

A minimal HTML5 validation wrapper for ng-form. Native checkValidity() drives the rules; the script paints the states and the messages. Link ng_form.js. For the markup itself see Form.

Once mounted, the script sets novalidate on the form and takes over: on submit every field is checked (an invalid form never submits); after the first interaction each field re-validates live on blur (text) or change (select/check). No rules to configure — use the native attributes: required, type="email", minlength, min/max, pattern

Live demo

Press Submit with empty fields: the invalid fields turn red with a generated message (ng-field-error + ng-help). Fix them and the state flips to ng-field-success. Every control type takes part: inputs, number, select, textarea, radios and the required checkbox.

At least 10 characters.
form.html
<form class="ng-form" id="fv-demo" action="#">
    <div class="ng-field mb-16">
        <label class="ng-label ng-label-required" for="fv-name">Name</label>
        <input type="text" class="ng-input" id="fv-name" name="name" required minlength="3">
    </div>
    <div class="ng-field mb-16">
        <label class="ng-label ng-label-required" for="fv-email">Email</label>
        <input type="email" class="ng-input" id="fv-email" name="email" required>
    </div>
    <div class="ng-field mb-16">
        <label class="ng-label" for="fv-age">Age</label>
        <input type="number" class="ng-input" id="fv-age" name="age" min="18" max="120">
    </div>
    <div class="ng-field mb-16">
        <label class="ng-label ng-label-required" for="fv-plan">Plan</label>
        <select class="ng-select" id="fv-plan" name="plan" required>
            <option value="">Choose…</option>
            <option value="starter">Starter</option>
            <option value="pro">Pro</option>
            <option value="enterprise">Enterprise</option>
        </select>
    </div>
    <div class="ng-field mb-16">
        <label class="ng-label ng-label-required" for="fv-msg">Message</label>
        <textarea class="ng-textarea" id="fv-msg" name="message" rows="3" required minlength="10"></textarea>
        <div class="ng-help">At least 10 characters.</div>
    </div>
    <div class="ng-field mb-16">
        <label class="ng-label">Contact me by</label>
        <label class="ng-check-nexi classic">
            <input type="radio" name="contact" value="email" checked>
            <span class="ng-check-box"></span> Email
        </label>
        <label class="ng-check-nexi classic">
            <input type="radio" name="contact" value="phone">
            <span class="ng-check-box"></span> Phone
        </label>
    </div>
    <div class="ng-field mb-16">
        <label class="ng-check-nexi bolder">
            <input type="checkbox" name="terms" required>
            <span class="ng-check-box"></span> I accept the terms
        </label>
    </div>
    <div class="ng-form-actions">
        <button type="submit" class="ng-btn ng-btn-primary">Submit</button>
    </div>
</form>

How it works

MountEvery ng-form is enhanced automatically; novalidate suppresses the browser bubbles.
RulesNative HTML5 attributes (required, type, minlength, pattern…) via checkValidity().
StatesThe wrapper ng-field gets ng-field-error or ng-field-success.
MessagesA ng-help with the native validation message is generated inside the field (data-ng-generated) and removed when the field becomes valid.
LiveRe-validation on blur for text controls, on change for selects and checks.
SubmitAn invalid form calls preventDefault() — it never reaches the server.

API

Exposed on each form element:

app.js
const form = document.querySelector('.ng-form');

form.ngValidate();   // validate every field, paint states → boolean
form.ngReset();      // clear all states and generated messages
form.ngSerialize();  // typed plain object from named controls

ngSerialize()

Returns a plain object built from every control with a name (buttons excluded). Values are typed by control — not the flat strings of FormData:

text / email / textareaString.
number / rangeNumber, or null when empty.
checkboxtrue / false (checked state).
radio groupValue of the checked radio, or null if none.
selectSelected option value (null if none); multiple → array of values.
fileArray of file names.
date / time / colorString value, or null when empty.

Filled with the demo form above, the output looks like this:

output.json
{
    "name":    "Jane Doe",        // text      → string
    "email":   "jane@acme.com",   // email     → string
    "age":     34,               // number    → Number (null if empty)
    "plan":    "pro",             // select    → option value (null if none)
    "message": "Hello there!",    // textarea  → string
    "contact": "email",           // radio     → checked value (null if none)
    "terms":   true              // checkbox  → boolean
}

Try it live — fill the demo form, then:

live output
// press the button…

Anatomy

ng-form ng-field ng-field-error ng-field-success ng-help[data-ng-generated]

API

form.ngValidate() form.ngReset() form.ngSerialize()