Short list
Up to 10 entries the radios stay visible. Arrow keys move, digits pick directly.
<fieldset data-gridselect>
<legend>Shipping</legend>
<label><input type="radio" name="ship" value="std" checked> Standard</label>
…
</fieldset>
gridselect(document.querySelector("[data-gridselect]"));
Multiple choice
Checkbox groups work the same way. Space or a digit toggles.
Long list with filter
More than 10 entries: a compact field opens a panel. Type to filter (try dollar or zur), arrows move through the grid, Enter or a digit picks.
Long list with highlight
Items never move, matches are marked. Good for lists people use every day.
<fieldset data-gridselect data-search="highlight"> … </fieldset>
Grid or flow
The default grid makes every column as wide as the widest entry, so short labels get as many columns as fit. data-layout="flow" lets the entries run one after another like chips, as dense as possible; arrow up and down jump to the nearest entry in the row above or below.
<fieldset data-gridselect> … </fieldset> <!-- grid, the default -->
<fieldset data-gridselect data-layout="flow"> … </fieldset>
Groups with headings
Options in <optgroup> get a heading in the panel, and each group starts a new row. The heading stays at the top while its group scrolls by. Works the same with items and <grid-select>.
<select name="currency">
<optgroup label="Europe">
<option value="EUR">Euro (EUR)</option> …
</optgroup>
<optgroup label="Americas"> … </optgroup>
</select>
Favourites on top
Pinned entries and the last picks appear on top with their own digits. They stay in the list as well, so positions there never change. Recent picks are stored in this browser only.
<fieldset data-gridselect data-pinned="EUR,USD" data-recent="currency"> … </fieldset>
A second line
Entries can carry a description under the label (description in items, data-description on an option). Screen readers hear it after the name. With data-search-description the search finds capitals too: try paris.
Pick several
Checkbox groups and <select multiple> get the same panel. Items toggle, the panel stays open, so you can filter and pick several in a row. data-max="3" stops at three: the rest is locked until you untick one.
As a custom element
Import @emmgeede/gridselect/element and write HTML. Works in plain pages and in React, Vue, Svelte or Angular.
<grid-select name="destination" label="Destination">
<option value="">Choose a destination…</option>
<option value="BER">Berlin (BER)</option>
…
</grid-select>
import "@emmgeede/gridselect/element";
Long labels
data-layout="list" stacks the items in one column.
From a plain select
An existing <select> keeps working in your form. The empty first option becomes the placeholder.