A searchable, accessible combobox (select with type-ahead filtering) for WeWeb. Bind any array of data, map label/value fields visually, and wire it into forms or workflows.
- Type-ahead search — filters options as the user types
- Single or multiple — multiple selection renders removable chips inside the field
- Keyboard navigation — Arrow keys, Enter, Escape, Tab all work as expected; Backspace removes the last chip
- ARIA-compliant —
role="combobox",aria-expanded,aria-controls,aria-activedescendant,aria-invalid, and named buttons - Floating dropdown — powered by Floating UI with auto-flip and scroll-shift
- Clear button — optional one-click reset
- Create option — lets users create new values when no match is found
- Custom option content — swap the built-in option row for your own dropzone layout, repeated per option
- Form integration — registers with WeWeb form elements for validation and submission
- Workflow actions — open, close, toggle, set value, reset, focus
- Local context — exposes
value,label,selectedOption,selectedOptions,multiple,isOpen,searchQuery, andoptionsto the formula editor - States —
focus,focus-visible,disabled,readonly,invalidfor style targeting
| Property | Type | Description |
|---|---|---|
| Options | Array | The list of choices ({ label, value, disabled }) |
| Label field | Formula | Maps the display label from a bound data source |
| Value field | Formula | Maps the stored value from a bound data source |
| Disabled field | Formula | Maps the disabled flag from a bound data source |
| Init value | Text | Pre-selects an option on mount. Option values, not labels — an array in multiple mode |
| Multiple | On/Off | Allow several selections, shown as removable chips. value becomes an array |
| Placeholder | Text | Input placeholder (multi-language) |
| Empty state text | Text | Message shown when no options match the search |
| Allow create | On/Off | Show a "Create" option when no option exactly matches the typed query |
| Create option label | Text | Label template for the create option — use {query} as a placeholder |
| Clearable | On/Off | Show a × button when a value is selected |
| Close on select | On/Off | Close the dropdown after picking an option |
| Keyboard on focus | Select | Touch screens. Auto: the virtual keyboard opens on focus. On demand: focus shows the options without the keyboard; a keyboard button in the field, or a second tap, opens it |
| Disabled | On/Off | Disable the entire combobox |
| Read only | On/Off | Show the value without allowing changes |
| Invalid | On/Off | Sets aria-invalid and applies the invalid state for validation styling |
| Required | On/Off | Mark the field as required for form submission |
| Accessible label | Text | Screen-reader name. Falls back to the form field name, then the element name |
| Clear button label | Text | Screen-reader name for the × button |
| Toggle button label | Text | Screen-reader name for the chevron button |
| Remove chip label | Text | Prefix for chip remove buttons — "Remove" announces as "Remove Banana" |
| Keyboard button label | Text | Screen-reader name for the keyboard button (On demand only) |
Turn on Style → Option → Custom content to design the option row yourself instead of using the built-in label + checked icon.
An Option dropzone then appears in the navigator. What you drop there is authored once and repeated for every option — it's a template, not a per-option layout. Bind text, images and styles to the repeat context:
| Binding | Value |
|---|---|
context.item.data.label |
The option's mapped label |
context.item.data.value |
The option's mapped value |
context.item.data.<key> |
Any other key of the option object (e.g. icon, count), as passed in choices |
context.item.index |
Its position in the filtered list |
The row wrapper keeps role="option", click-to-select, hover highlighting, keyboard navigation and the is-selected / is-active / is-disabled classes — so the Option style properties (background, hover/selected background, padding, border radius) all still apply. Only the row's contents become yours.
- Label field is still required. Search filtering, the input's displayed text and multi-select chips all read the mapped label, whether or not you render it.
- No built-in selection mark. The checked icon is part of the built-in row. Selected options still get the selected background from the style panel; add your own indicator inside the dropzone if you want a mark.
isSelectedis not yet exposed in the repeat context. - Keep dropped elements non-focusable. The combobox holds focus on the search input and points at the active option with
aria-activedescendant. Aww-buttonor input inside an option steals that focus and breaks keyboard navigation — preferww-text,ww-image,ww-div. - Options are announced by their mapped label via
aria-labelon the row, so an icon-only row is still named. - Authoring tip: turn on Force open (Settings → Behavior) to keep the dropdown open on the canvas while you build the row. While custom content is on, the dropdown renders in place rather than teleporting, so drag & drop and selection work; at runtime it always teleports.
Turning the toggle back off keeps the dropped elements — they stay stored on the element and reappear when you re-enable it.
The dropdown is fully customisable from the style panel, grouped into:
- Input — font size, font weight, placeholder color, icon color, icon size, chevron icons (closed/open), icon button background and border radius (default and hover)
- Dropdown — position, offset, width, max height, background, border, radius, padding, shadow, z-index
- Option — custom content toggle (see above), font size, font weight, text color, background, hover/selected variants, padding, border radius, checked icon (icon, color, size)
- Empty state — font size, text color, padding
- Chips (multiple mode) — background, text color, font size/weight, height, radius, padding, gap, label-to-icon gap, remove icon color/hover/size
- Create option — font size, font weight, text color, background, hover background, create icon and its color/size
Focus styling is yours to define — the component ships no focus ring of its own.
The focus-visible state activates only when focus arrived by keyboard (the
browser's own :focus-visible heuristic decides), while focus activates however
focus arrived. Select focus-visible in the state picker and set outline from the
native style panel to get a keyboard-only focus ring.
Leave both states unstyled and there is no visible keyboard focus indicator, which is a WCAG 2.4.7 failure. States apply to the component root, so they style the field but not the chevron and clear buttons.
| Event | Payload | When |
|---|---|---|
| On change | { value } |
User selects or clears an option |
| On init value change | { value } |
The bound init value changes |
| On focus | — | Input receives focus |
| On blur | — | Input loses focus |
| On dropdown open | — | Dropdown opens |
| On dropdown close | — | Dropdown closes |
| On search | { value } |
User types in the input |
| On create | { value } |
User confirms a new value via the create option |
| On chip remove | { value } |
A chip is removed (fires alongside On change). Multiple mode only |
On create does not add the option. It only reports the typed value — append it to whatever backs Options in a workflow, then set the value.
| Action | Arguments | Description |
|---|---|---|
| Open | — | Open the dropdown |
| Close | — | Close the dropdown |
| Toggle | — | Toggle open/closed |
| Set value | value |
Select an option by value (an array in multiple mode) |
| Reset value | — | Clear the current selection. Does not focus the field or open the dropdown |
| Focus | — | Focus the input |
| Show keyboard | — | Focus the input with the virtual keyboard open. May do nothing on iOS (see below) |
Keyboard on demand. The field focuses with
inputmode="none", then switches totextand re-focuses when the keyboard is asked for. iOS only raises the keyboard for a focus made inside the tap itself, so the keyboard button and the second tap work everywhere, while Show keyboard from a workflow (which runs after the tap) may not on iPhone. The keyboard button only shows on touch screens, and always in the editor. Leaving the combobox resets it to no keyboard.
Access component state in formulas via context.local.data?.['combobox']:
# Install dependencies
npm i
# Serve locally (add to WeWeb via the developer popup)
npm run serve -- port=3100
# Check for build errors before release
npm run build -- name=combobox type=wwobjectThe CLI parses bare
name=/port=args, not--name=/--port=. Passing--name=comboboxfails witharg 'name="name"' not specified.
