Forms
Summary
Form layout primitives for labels, inputs, validation messages,
help text, and grouped controls (radios, checkboxes). Three
layout variants (default, top-label, long-label) cover most
rendering needs from narrow popovers to wide settings pages.
Width modifiers (-short, -medium,
-long, -full) constrain inputs to
sensible defaults.
When to use
| Layout | Use it for |
|---|---|
Default.neura-form | Standard side-by-side label / input layout. Sensible default for most forms. |
Top-label.neura-form-top-label | Stacks labels above inputs. Use in narrow containers (inline dialog, sidebar). |
Long-label.neura-form-long-label | Reserves more horizontal room for the label column. Use when label text wraps awkwardly. |
Examples
Live form fields with every input variant, width modifier, and help / error treatment. Inputs aren't wired to a backend: focus a field, try the disabled + file pickers, and toggle the date input to verify the chrome.
Text inputs
Dropdowns and multi select
Textarea
Radio buttons
Checkboxes
File upload
HTML
Field group: wraps label, input, optional help text and error.
<form class="neura-form">
<div class="neura-field-group">
<label for="email">Email<span class="icon-required"> (required)</span></label>
<input type="email" id="email" class="neura-field-text">
<div class="neura-field-description">We never share your email.</div>
</div>
</form>
Width modifiers go on the input itself:
<input class="neura-field-text neura-field-short"> <!-- 75px -->
<input class="neura-field-text neura-field-medium"> <!-- 165px -->
<input class="neura-field-text neura-field-long"> <!-- 500px -->
<input class="neura-field-text neura-field-full"> <!-- 100% of group -->
For a validation error, append a .neura-field-error below the input:
<div class="neura-field-group">
<label for="pw">Password</label>
<input type="password" id="pw" class="neura-field-password">
<div class="neura-field-error">Must be at least 8 characters.</div>
</div>
Top-label layout (use in narrow containers):
<form class="neura-form neura-form-top-label">
<div class="neura-field-group">
<label for="search">Search</label>
<input type="search" id="search" class="neura-field-text neura-field-full">
</div>
</form>
For a radio group, wrap each radio + label in .neura-field-radio:
<div class="neura-field-group">
<label>Radio buttons</label>
<div class="neura-field-radio">
<input type="radio" id="r-blog" name="save-target" value="blog" checked>
<label for="r-blog">Save as a blog post</label>
</div>
<div class="neura-field-radio">
<input type="radio" id="r-page" name="save-target" value="page">
<label for="r-page">Save as a page</label>
</div>
<div class="neura-field-radio">
<input type="radio" id="r-draft" name="save-target" value="draft">
<label for="r-draft">Save to your drafts</label>
</div>
</div>
Checkbox groups use the same pattern with .neura-field-checkbox:
<div class="neura-field-checkbox">
<input type="checkbox" id="cb-email">
<label for="cb-email">Receive email</label>
</div>
For the buttons row, group form submit + cancel in .neura-buttons-container:
<div class="neura-buttons-container">
<button type="submit" class="neura-button">Save</button>
<button type="button" class="neura-button neura-button-link">Cancel</button>
</div>
CSS classes
Form layouts
| Class | Effect |
|---|---|
.neura-form | Default: labels left of inputs. |
.neura-form-top-label | Stacks labels above inputs. |
.neura-form-long-label | Wider label column. |
.neura-field-group | Wraps a single label + input + help + error. |
.neura-fieldset-group | On a <fieldset>: groups radio/checkbox sets with the <legend> floated into the label column (the a11y-correct grouping; screen readers announce the legend with each option). Legends render only inside this construct, matching AUI. |
.neura-buttons-container | Aligns submit / cancel buttons at the form footer. |
Inputs
| Class | Effect |
|---|---|
.neura-field-text | Text input baseline. |
.neura-field-password | Password input baseline (same shape as text). |
.neura-field-textarea | Multi-line input. |
.neura-field-select | Single-value <select>. |
.neura-field-multiselect | Multi-value <select multiple>. |
.neura-field-file | File upload: keeps the native widget. |
.neura-field-radio | Wraps a single radio + label pair. |
.neura-field-checkbox | Wraps a single checkbox + label pair. |
Width modifiers
| Class | Width |
|---|---|
.neura-field-short | 75px |
.neura-field-medium | 165px |
.neura-field-long | 500px |
.neura-field-full | 100% of the field group |
Help text and validation
| Class | Effect |
|---|---|
.neura-field-description | Help text below the input (gray). |
.neura-field-error | Validation error message (red). |
.icon-required | Renders the red asterisk after a required field's label. |
JavaScript
Forms are CSS-only: there is no Neura.form(...)
API. Wire your own submit handler with
addEventListener. For the calendar input, see
the dedicated Date picker page.
Form submit pattern:
<form id="signup-form" class="neura-form">
<!-- ... fields ... -->
<div class="neura-buttons-container">
<button type="submit" class="neura-button neura-button-primary">Sign up</button>
<button type="button" class="neura-button neura-button-link" id="cancel">Cancel</button>
</div>
</form>
<script>
document.getElementById('signup-form').addEventListener('submit', (e) => {
e.preventDefault();
const data = new FormData(e.currentTarget);
fetch('/signup', { method: 'POST', body: data });
});
</script>
Inline help: hide longer guidance behind a help icon next to
the input (the Email field above wires exactly this snippet).
The icon toggles a hidden description and keeps
aria-expanded in sync:
<span class="neura-icon neura-icon-help" role="button" tabindex="0"
aria-controls="email-help" aria-expanded="false"
aria-label="Toggle help"></span>
<div class="neura-field-description neura-hidden" id="email-help">
We only use your address for account notifications - never marketing.
</div>
document.querySelectorAll('.neura-form [role="button"][aria-controls]').forEach((btn) => {
const help = document.getElementById(btn.getAttribute('aria-controls'));
const toggle = () => {
const hidden = help.classList.toggle('neura-hidden');
btn.setAttribute('aria-expanded', String(!hidden));
};
btn.addEventListener('click', toggle);
btn.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggle(); }
});
});
AUI compatibility
All .aui-* form classes (.aui-form,
.aui-field-text, etc.) and form.aui
field hooks alias to the Neura rules, including the grouped
controls (fieldset.group + legend →
.neura-fieldset-group), the
.radio/.checkbox row wrappers, the
legacy .button (routed onto
neura-button), the .cancel link, and
the .buttons whitespace handling. Existing
Velocity templates render unchanged. AJS.inlineHelp() keeps
the legacy .icon-inline-help /
.field-help markup toggling; new code should use
the inline-help pattern above instead.