the form builder
JavaScript form builder: validation and layouts
Lay a form out as fieldsets, rows and columns, give each field a control that fits it, and check it all when the user presses Save. The form below is live: leave the required fields empty and submit it, then fill it in and submit again.
rows and cols
Rows stack, cols sit side by side.
A form is a tree of rows and cols, each
nesting the other to any depth. A rows block stacks its children top
to bottom. A cols block places them side by side and shares the width
equally unless a child sets its own, and the shell module reads the two words the same way.
Give a child a percentage width and it takes that share of the row, so three items of
33.3% sit on one line. Below a container width you choose, a cols block
stacks into a single column.
what the form gives you
The controls a record needs, and the checks behind them.
Controls
Text, email, password and url inputs, number, textarea, checkbox, toggle, select, radio and checkbox groups, rating, a stage pipeline, chips, a searchable combo, date, date-time and time pickers, one-time-code entry, buttons, and a sanitised rich-text editor.
Layouts
Fieldsets, rows, cols, spacers and separators. Widths in percent, or in pixels, or flexible. Density levels of compact, standard and comfortable, and a form beside a grid follows that grid’s row height.
Labels where you want them
Labels on the left or on top, at a width you set, or hidden from view while staying the field’s accessible name. Set it for the form, a fieldset or one item.
Number formats and units
A number field shows currency, percent or fixed decimals while it is not focused and stores a plain number. A unit-aware field converts what is typed, so 145 psi into a bar field stores the value in bar, and a temperature scale converts too.
Disabled and read-only
One contract for every control. Disabled leaves the tab order and is skipped by validation. Read-only stays focusable and selectable, refuses every change, and still validates and still appears in the values. Set them per item or for the whole form.
Validation
Required fields, built-in rules for email, number, integer and url, a regular expression, or a function that returns a message. Check on submit, on change or on blur. Failures carry aria-invalid and a message beside the field.
Rules that react
visibleWhen, readOnlyWhen and requiredWhen re-run on every committed change, so a field can appear, lock or become required from the value of another.
A stepper for long forms
Give the form a list of steps and it becomes a wizard under a step indicator, horizontal or vertical. Next validates the current step first, Back never does, and the last step reads Finish.
Bound to a grid or the data router
Bind a form to a grid row and it builds one item per column when you declare no layout, tracks which items are dirty, and saves through the grid’s own edit path. Bind it to a data router record and it follows the feed without overwriting what a user is typing.
Files and combos
A file drop area accepts drop, paste or pick, enforces type, size and count, and shows progress with retry and remove. A combo pages and searches a server list, takes avatars, icons and dots on its options, and can allow new entries.
Every framework, and htmx
Wrappers for React, Vue, Svelte and Angular. On an htmx page, a server-rendered form is enhanced in place with a data attribute, keeping its field names and its posts, with validation before the post goes out.
a form from a config
Describe the fields, get the form.
Drop in one script tag, then hand createForm your rows. Every item
is in the document and measurable when the call returns, so there is no redraw to wait for.
Read the values with getValue(), write them with
setValue(), and listen for change or
submit.
The form is a separate, opt-in module with a global of its own. See its size next to every other module in the module map.
<!-- the form module, as a global -->
<script src="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1/modules/form.min.js"></script>
<script>
var form = LatticeGridForm.createForm(document.querySelector('#deal'), {
rows: [
{ fieldset: 'Opportunity', cols: [ // cols sit side by side
{ type: 'input', name: 'name', label: 'Name', required: true, width: '33.3%' },
{ type: 'input', name: 'account', label: 'Account', required: true, width: '33.3%' },
{ type: 'combo', name: 'owner', label: 'Owner', options: people, width: '33.3%' }
] },
{ type: 'number', name: 'amount', label: 'Amount',
format: { style: 'currency', currency: 'USD' }, min: 0 },
{ type: 'buttons', align: 'end', items: [
{ name: 'save', label: 'Save', variant: 'primary', buttonType: 'submit' }
] }
]
});
// A submit button validates first, then fires submit with the values.
form.el.addEventListener('submit', function (e) { save(e.detail.values); });
</script>
Build the form on localhost, free.
Development on localhost needs no licence key, so you can lay out a real record and see it validate before you decide anything. Licence per domain when you ship.
The application layout Drive it from one feed Use it with htmx The dashboard designer All modules Documentation