StringForm Module

Declarative, HTML-first validation for complex forms. StringForm reads rule strings from your markup, filters keystrokes in real time, mirrors error states in CSS, and emits events once everything is valid.

Activation primer: Add string="form" to every <form> you want StringForm to manage. Supply string-id="your-id" when you need a stable handle for events, mirrors, or string-copy-from; otherwise StringTune generates one automatically.

HTML Attributes

AttributeTargetDefaultControlsPractical notes
string-input="rule|list"<input>, <select>, <textarea>""Pipe-delimited validation rulesWorks with native attributes (required, type) but enforces extra rules
string-input="group[key]"Any containerMirrors the state of the field mapped by key (-error, -valid)Match key to the field id or name; useful for wrapping labels/helpers
string-input="error[key]"Any elementReceives rendered error <span> nodes for the field referenced by keyKeeps markup clean and avoids manual error message wiring

Module Snapshot

  • Activation attribute: string="form"
  • Field discovery: scans descendants with string-input, excluding helper targets (group[*], error[*])
  • Class states: -inited (initialised), -valid, -error toggle on both inputs and their mapped groups
  • Input filtering: intercepts beforeinput to block invalid keystrokes for live rules like pattern or number
  • Submission gate: prevents default submit, validates every field, focuses the first invalid control, and emits events
  • Data output: form:submit:<id> payload is a flat object respecting checkbox arrays, multi-select lists, and radio groups

Basic Usage

import StringTune, { StringForm } from '@fiddle-digital/string-tune';

const stringTune = StringTune.getInstance();
stringTune.use(StringForm);
stringTune.start(60);
<form string="form" string-id="contact">
  <div class="field" string-input="group[name]">
    <label for="name">Name</label>
    <input id="name" name="name" string-input="required|min:2" autocomplete="name" />
    <p class="error" string-input="error[name]"></p>
  </div>

  <div class="field" string-input="group[email]">
    <label for="email">Email</label>
    <input id="email" name="email" type="email" string-input="required|email" />
    <p class="error" string-input="error[email]"></p>
  </div>

  <fieldset class="field" string-input="group[contact-pref]">
    <legend>Preferred contact</legend>
    <label><input type="radio" name="contact-pref" value="phone" string-input="required" /> Phone</label>
    <label><input type="radio" name="contact-pref" value="email" string-input="required" /> Email</label>
    <p class="error" string-input="error[contact-pref]"></p>
  </fieldset>

  <button type="submit">Send</button>
</form>
.field {
  display: grid;
  gap: 6px;
}

.field.-error input,
.field.-error textarea,
.field.-error select {
  border-color: #d64949;
}

.error {
  min-height: 1.25rem;
  color: #d64949;
  font-size: 0.85rem;
}

input.-valid {
  border-color: #2f9b59;
}

Rule Library

Combine rule tokens with | (e.g. required|min:3|email). You can extend the parser globally via settings, but the built-ins cover most patterns.

RulePurpose
requiredRejects empty strings, unchecked radios/checkboxes, or empty arrays
checkedForces a checkbox-style field to be explicitly acknowledged
numberAllows only digits, optional decimal point, and leading minus (guards both typing and submission)
integerFilters typing to whole numbers; pair with number if you also need submit-time enforcement
emailBasic email format guard; complements native type="email"
phoneRestricts to digits, spaces, +, -, (, ) with limited plus signs
letters / lettersSpaces / lettersNumbersKeystroke filters for alphabetic characters (submit-time validation not enforced)
urlPermits URL-safe characters and validates structure on submit
min:x / max:xLength constraints for string values
pattern:/.../Custom RegExp guard during typing; combine with other rules for submit-time validation

Rules run both during beforeinput (to stop illegal characters) and on submit, ensuring consistent enforcement.

How It Works

  • Field mapping: each control gets a stable key based on string-id, id, or name; this key wires up group and error targets.
  • Live validation: on input/change the module re-validates the control, updates error text, and toggles CSS classes.
  • Keystroke guards: beforeinput interception prevents the user from entering disallowed characters, keeping values clean.
  • Submission flow: submit is intercepted, all fields re-validated, the first invalid control focused, and events raised accordingly.
  • Cleanup ready: listeners are tracked in form-events so disconnecting the object removes hooks automatically.

Event Signals

Channel patternPayloadFired whenUse cases
form:submit:<id>{ [key: string]: string | string[] | boolean }Form passes validation during submitSend payload via fetch, trigger success UI, analytics
form:invalid:<id>voidSubmit attempted with at least one invalid fieldShake form, show toast, scroll to first error
stringTune.on('form:submit:contact', (data) => {
  console.log('Form ready', data);
});

stringTune.on('form:invalid:contact', () => {
  console.warn('Please revise the highlighted fields.');
});

StringForm keeps validation declarative—describe your constraints inline, style via the emitted classes, and rely on the submit events to bridge into your app logic.