JavaScript form library: 5 new controls, 1.101
A JavaScript form library is rarely the only thing a screen needs. Somewhere between the first sprint and the tenth, the form wants a date range, a pick-and-move list, a floating action button, a labelled switch, and the warehouse wants a barcode in a grid cell. The usual answer is to bolt on a second widget kit for each gap. Then you own two sets of themes, two keyboard models, two sets of focus rules and two ways to be wrong about dark mode.
Five new controls ship in this release, in the same form and grid you already load. Every example below is live.
Why one library should carry them
A control from a second kit does not know about your form. It does not take part in validation, it ignores your read-only lock, it reads its colours from somewhere else, and it adds a stylesheet and a bundle you have to keep patched. A control inside the form is one more item type. It commits through the same change event, honours beforeChange, follows the density and the light and dark tokens, and reads back through the same getValue(). Nothing to glue. The grid engine underneath is the same one, so the barcodes below are a column renderer, not an add-on.
A date range picker with presets and span limits
One field holds a start and an end. Pick them in the popup, two months side by side, or type them. In the example at the top of the page, presets sit down the left side of the first picker, and the second limits the stay to between two and fourteen days. Try picking a single day, then a three-week span.
The value is { start, end } as ISO strings, so it goes into a query or a filter without parsing. Apply and Cancel keep half-finished picks out of your state, and a month-range mode covers reports that run by month.
{ type: 'daterange', name: 'stay', label: 'Stay',
minSpan: 2, maxSpan: 14, min: '2026-10-13', weekNumbers: true,
presets: [{ label: 'Next 7 days', range: () => [today(), inDays(6)] }] }
A list box with checkboxes, a filter and two connected lists
Some choices are too long for a dropdown and too structured for a text box. The list box is an always-visible list with single, multiple or checkbox selection, a filter box, group headers, sorting and reordering. Name another list in connect and the pair passes items between them, by button or by drag. Below, choose which columns an export includes and in which order.
Each side reads back as the items it currently holds, so the right-hand list is already your column order. The filter never drops an item you selected and then hid by searching.
A speed dial on its own and inside a form
A floating action button that opens a short list of actions. It anchors to any corner or edge, opens as a strip or a radial fan, can dim the page behind it, and comes in seven colours. It is reachable by keyboard: arrows move across the actions, Enter picks one and Escape closes the menu and returns focus. On the left it stands alone in a container. On the right it is an item of a form.
const dial = createSpeedDial(panel, {
items: [{ id: 'edit', icon: 'pencil', text: 'Edit' }, { id: 'share', icon: 'share', text: 'Share' }],
position: 'bottom-right', direction: 'up',
});
dial.on('itemClick', (e) => run(e.item.id));
A toggle with on and off text and variants
The toggle switch can now say what it means. Put short text inside the track or beside it, pick one of three sizes and one of three track shapes, and the label swaps with the state. A tick and a cross, ON and OFF, or Yes and No, whichever your users read fastest. Contrast against the track holds in light and dark, and the slide respects reduced motion.
A grid column of barcodes, and a Data Matrix
A warehouse grid with a SKU in text is half a grid. The barcode renderer draws Code 39, Code 93, Code 128, EAN, UPC and more as inline SVG straight from the row value, and the same engine draws Data Matrix beside the QR renderer you already have. Because it is a cell, it draws from the row beside it and follows the theme like any other column. A value that is invalid for its symbology, such as a wrong EAN check digit, shows a placeholder and warns instead of drawing a code that would scan wrong.
{ field: 'ean', title: 'EAN-13',
cell: { render: 'barcode', props: { type: 'ean13', height: 44 } } }
The same drawing is available outside a grid through renderBarcode(el, options), and inside a form as a display control, so a label prints the way it looked on screen.
What it means for your app
Five fewer reasons to add a second widget kit, and the same theming, keyboard and validation across all of them. Install it and open the form page:
npm install @toclocoinc/lattice-grid
The form builder page lists every control, and the full set of changes is in the changelog.