Example 1: Contact Form (Declarative)
Basic contact form with validation and success message - No JavaScript needed
HTML Code:
<!-- Contact Form - Zero JavaScript! -->
<form
data-form="contact"
data-action="api/contact.php"
data-method="POST"
data-ajax-submit="true"
data-reset-after-submit="true"
data-success-message="Thank you!"
data-show-success-in-notification="true"
data-prevent-double-submit="true">
<fieldset>
<div>
<label for="contact_name">Name</label>
<span class="form-control icon-customer">
<input type="text" id="contact_name" name="name"
required minlength="2" maxlength="100"
data-error-required="Please enter your name">
</span>
</div>
<div>
<label for="contact_email">Email</label>
<span class="form-control icon-email">
<input type="email" id="contact_email" name="email"
required
data-error-required="Please enter your email"
data-error-email="Invalid email address">
</span>
</div>
<div>
<label for="contact_message">Message</label>
<span class="form-control icon-comment">
<textarea id="contact_message" name="message"
rows="4" required minlength="10"
data-error-required="Please enter your message"></textarea>
</span>
</div>
</fieldset>
<fieldset class="form-actions submit right">
<button type="submit" class="btn btn-primary icon-send">Send</button>
</fieldset>
</form>
Example 2: Login Form (Zero JavaScript)
Complete login form using exact patterns from dashboard/crm examples - No JavaScript required!
Login Form Pattern (No JavaScript!):
<!-- Complete login form - Zero JavaScript required! -->
<form
data-form="login"
class="auth-form"
novalidate
action="api/v1/auth/login"
method="post"
data-ajax-submit="true"
data-redirect="/"
data-auto-fill-intended-url="true">
<!-- Welcome message -->
<p class="login-message">Welcome back!</p>
<fieldset>
<div>
<label for="login_username">Username/Email</label>
<span class="form-control icon-email">
<!-- data-persist: Remember username in localStorage -->
<input type="text" id="login_username" name="username"
autocomplete="username" autofocus
data-persist="local"
data-persist-key="login_username"
data-persist-ttl-days="30">
</span>
</div>
<div>
<label for="login_password">Password</label>
<span class="form-control icon-password">
<input type="password" id="login_password" name="password"
autocomplete="current-password">
</span>
</div>
<div>
<div class="input-groups">
<div class="width50">
<!-- switch: Toggle style, data-persist: Remember state -->
<input type="checkbox" id="remember" class="switch"
name="remember" value="1"
data-persist="local"
data-persist-key="login_remember">
<label for="remember">Remember Me</label>
</div>
<div class="width50 right">
<a href="forgot">Forgot Password</a>
</div>
</div>
</div>
</fieldset>
<fieldset class="center">
<button type="submit" class="btn btn-primary fullwidth large icon-signin">Log in</button>
</fieldset>
</form>
Login Form Attributes
| Attribute | Description |
|---|---|
data-form="login" |
Identifies form for FormManager (required) |
data-ajax-submit="true" |
Submit via AJAX instead of page reload |
data-redirect="/" |
Where to redirect on success |
data-auto-fill-intended-url="true" |
Auto-fill hidden field with URL user tried to access |
data-persist="local" |
Persist field value in localStorage |
data-persist-key="..." |
Custom key for localStorage |
data-persist-ttl-days="30" |
Expiry time in days |
class="login-message" |
Styled welcome message |
class="switch" |
Toggle switch style for checkbox |
novalidate |
Disable browser validation, use FormManager instead |
Example 3: Validation Types
Demonstrating all built-in validation types with custom error messages
Validation Attributes:
<!-- Required -->
<!-- Required field -->
<div>
<label for="name">Name</label>
<span class="form-control icon-customer">
<input id="name" name="name" required
data-error-required="This field is required">
</span>
</div>
<!-- Length validation -->
<div>
<label for="username">Username</label>
<span class="form-control">
<input id="username" name="username"
minlength="3" maxlength="20"
data-error-minlength="Minimum 3 characters"
data-error-maxlength="Maximum 20 characters">
</span>
</div>
<!-- Email validation -->
<div>
<label for="email">Email</label>
<span class="form-control icon-email">
<input type="email" id="email" name="email"
data-error-email="Invalid email">
</span>
</div>
<!-- Number range -->
<div>
<label for="age">Age</label>
<span class="form-control">
<input type="number" id="age" name="age"
min="18" max="100"
data-error-min="Must be at least 18"
data-error-max="Must be no more than 100">
</span>
</div>
<!-- Password with confirm -->
<div class="input-groups">
<div class="width50">
<label for="password">Password</label>
<span class="form-control icon-password">
<input type="password" id="password" name="password"
data-element="password"
data-password-strength="bar">
</span>
</div>
<div class="width50">
<label for="confirm">Confirm</label>
<span class="form-control icon-password">
<input type="password" id="confirm" name="confirm"
data-target-password="password"
data-error-match="Passwords do not match">
</span>
</div>
</div>
Example 4: Confirmation Dialog
Form that asks for confirmation before submitting
Confirmation Attribute:
<form
data-form="delete-account"
data-method="DELETE"
data-ajax-submit="true"
data-confirm="Are you sure? This cannot be undone."
data-success-message="Account deleted"
data-redirect="/">
<fieldset>
<div class="alert alert-warning">
<span class="icon-warning"></span>
<span>Warning: This action is permanent.</span>
</div>
<div>
<label for="delete_confirm">Type "DELETE" to confirm</label>
<span class="form-control">
<input type="text" id="delete_confirm" name="confirmation"
required pattern="^DELETE$"
data-error-required="Please type DELETE"
data-error-pattern="Please type exactly: DELETE">
</span>
</div>
</fieldset>
<fieldset class="submit right">
<button type="button" class="btn" onclick="history.back()">Cancel</button>
<button type="submit" class="btn btn-danger icon-trash">Delete</button>
</fieldset>
</form>
Example 5: URL Parameters Loading
Load form values from URL query parameters (e.g., password reset links)
URL Parameters Attributes:
<!-- URL: /reset-password?token=abc123&uid=42 -->
<form
data-form="reset-password"
data-ajax-submit="true"
data-load-url-params="true"
data-url-params-required="true"
data-url-params-required-fields="token,uid">
<!-- Hidden fields auto-filled from URL params -->
<input type="hidden" name="token" data-attr="value:token">
<input type="hidden" name="uid" data-attr="value:uid">
<fieldset>
<div class="input-groups">
<div class="width50">
<label for="reset_password">New Password</label>
<span class="form-control icon-password">
<input type="password" id="reset_password" name="password"
required minlength="8"
data-element="password"
data-password-strength="bar">
</span>
</div>
<div class="width50">
<label for="reset_confirm">Confirm Password</label>
<span class="form-control icon-password">
<input type="password" id="reset_confirm" name="confirm"
required
data-target-password="reset_password"
data-error-match="Passwords do not match">
</span>
</div>
</div>
</fieldset>
<fieldset class="submit right">
<button type="submit" class="btn btn-primary icon-save">Reset Password</button>
</fieldset>
</form>
Example 6: Edit Profile (API Integration)
Advanced form with API data loading and file upload
This example requires a backend API endpoint. See documentation for API response format.
API Integration Attributes:
<form
data-form="editprofile"
data-action="api/v1/form/update"
data-load-api="api/v1/form"
data-ajax-submit="true">
<!-- Fields with data-attr bind to API response -->
<input name="name" data-attr="value:name">
<input name="email" data-attr="value:email">
<!-- Select with dynamic options -->
<select name="gender" data-options-key="genders">
<option value="">Select...</option>
</select>
<!-- File upload with preview -->
<input type="file" name="avatar"
data-preview="true"
data-allow-remove-existing="true">
<!-- Hidden ID field -->
<input type="hidden" name="id" data-attr="value:id">
</form>
Recommended HTML Structure
Follow these HTML patterns for proper form styling and JavaScript integration
Structure Patterns:
<!-- ===== FORM CONTAINER ===== -->
<form data-form="formId" data-ajax-submit="true">
<!-- ===== FIELDSET: Groups related fields ===== -->
<fieldset>
<legend>Section Title</legend>
<!-- SINGLE FIELD PATTERN -->
<div>
<label for="fieldId">Label</label>
<span class="form-control icon-name">
<input type="text" id="fieldId" name="fieldName">
</span>
<div class="comment">Help text</div>
</div>
</fieldset>
<!-- ===== SIDE-BY-SIDE FIELDS ===== -->
<fieldset>
<div class="input-groups">
<div class="width50"> <!-- 50% width -->
<label>First Field</label>
<span class="form-control">
<input type="text" name="field1">
</span>
</div>
<div class="width50"> <!-- 50% width -->
<label>Second Field</label>
<span class="form-control">
<input type="text" name="field2">
</span>
</div>
</div>
</fieldset>
<!-- ===== SUBMIT ACTIONS ===== -->
<fieldset class="submit right">
<button type="reset" class="btn">Reset</button>
<button type="submit" class="btn btn-primary">Save</button>
</fieldset>
</form>
HTML Structure Reference
| Pattern | Description | Usage |
|---|---|---|
<fieldset> |
Groups related form fields | Wrap sections of related inputs |
<legend> |
Section title inside fieldset | Label for field groups |
fieldset.submit |
Submit button container | Wrap submit/reset buttons |
.right |
Align content to right | Add to .submit for right alignment |
span.form-control |
Input wrapper (REQUIRED) | Wrap every input/select/textarea |
.icon-{name} |
Input icon | Add to form-control for icons |
.input-groups |
Side-by-side container | Flexbox container for columns |
.width50 |
50% width column | Use inside input-groups |
.width33 |
33% width column | For 3-column layouts |
.comment |
Help/hint text below field | Place after form-control span |
id="result_{fieldId}" |
Error message container | FormError displays errors here |
data-element Attribute
The data-element attribute enables JavaScript-enhanced functionality for specific input types:
| Element Type | Additional Attributes | Description |
|---|---|---|
data-element="password" |
data-password-strength="bar"data-password-criteria-list="true"data-target-password="fieldId"
|
Password with strength meter and/or confirmation matching |
data-element="file" |
data-preview="true"data-allow-remove-existing="true"data-file-reference="url"
|
File upload with preview and remove functionality |
data-element="autocomplete" |
data-options-key="keyName"data-api="endpoint"
|
Autocomplete input with API or predefined options |
Quick Reference: Form Data Attributes
| Attribute | Description | Example |
|---|---|---|
data-form |
Form ID (required) | "contact" |
data-ajax-submit |
Submit via AJAX | "true" |
data-confirm |
Confirmation dialog | "Are you sure?" |
data-reset-after-submit |
Reset form after success | "true" |
data-success-message |
Success notification | "Saved!" |
data-redirect |
Redirect after success | "/dashboard" |
data-load-url-params |
Load values from URL | "true" |
data-prevent-double-submit |
Prevent duplicate submissions | "true" |
| Input Attribute | Description | Example |
|---|---|---|
data-error-required |
Custom required message | "Please fill this" |
data-error-email |
Custom email error | "Invalid email" |
data-error-minlength |
Minimum length error | "Too short" |
data-error-pattern |
Pattern mismatch error | "Invalid format" |
data-target-password |
ID of password to match | "password" |
data-attr |
Bind to API data | "value:fieldname" |