Combobox
Searchable choice with APG behavior; stale remote options cannot overwrite current input.
Use the web element directly without the semantic runtime.
A registered presentation adapter can bind this component to host-owned meaning and state.
The standard recipe resolver does not select this component automatically.
Import and live example#
One open person combobox with a query draft and bounded options.
Interactive preview requires JavaScript.
View the complete example source
import {registerAeliqoElements} from "@varendo/web";
import {
AeliqoCheckboxElement,
AeliqoComboboxElement,
AeliqoDateFieldElement,
AeliqoDateRangeElement,
AeliqoFieldGroupElement,
AeliqoFileInputElement,
AeliqoFormElement,
AeliqoNumberFieldElement,
AeliqoRadioGroupElement,
AeliqoSearchFieldElement,
AeliqoSelectElement,
AeliqoSliderElement,
AeliqoSwitchElement,
AeliqoTextAreaElement,
AeliqoTextFieldElement,
type AeliqoOption,
} from "@varendo/web/inputs";
const options: readonly AeliqoOption[] = [
{value: "ada", label: "Ada Lovelace", description: "Research"},
{value: "grace", label: "Grace Hopper", description: "Product"},
{value: "lin", label: "Lin Chen", disabled: true},
];
registerAeliqoElements();
const host = document.querySelector<HTMLElement>("#aeliqo-example") ?? (() => {
const created = document.createElement("div");
created.id = "aeliqo-example";
(document.body ?? document.documentElement).append(created);
return created;
})();
function createCatalogRoot(container: HTMLElement): HTMLElement {
const root = document.createElement("div");
root.dataset.catalogSourceRoot = "true";
root.style.display = "grid";
root.style.gap = "12px";
container.append(root);
return root;
}
function createCatalogElement<T extends HTMLElement>(tagName: string, container: HTMLElement): T {
const element = document.createElement(tagName) as T;
element.setAttribute("data-aeliqo-theme", "light");
container.append(element);
return element;
}
function appendSlottedText(root: HTMLElement, slot: string, textContent: string): void {
const content = document.createElement("span");
content.slot = slot;
content.textContent = textContent;
root.append(content);
}
const root = createCatalogRoot(host);
(((root) => {
const element = createCatalogElement<AeliqoComboboxElement>("aeliqo-combobox", root);
element.label = "Person";
element.name = "person";
element.options = options;
element.value = "ada";
element.query = "Ada";
element.open = true;
element.minQueryLength = 1;
}))(root);
Purpose#
A searchable choice field with separate local query and selected value properties. The host can
set the selected value; typing clears it, while choosing an option updates it and emits a typed
change. Late remote responses are ignored, so stale options do not replace current results; the host
owns query sourcing and persistence.
When to use it#
- People pick one option from a list too long to read at once.
- Typing a query should filter the option list.
- Options may load remotely and responses can arrive late.
- The query draft and the committed value must stay separate.
When to use a different component#
- Use Select for a short list that needs no query.
- Use SearchField when the query itself is the value and no option is committed.
Properties and defaults#
query is a draft separate from the selected value. Supply bounded options or a host-owned optionsLoader; stale loader results are cancelled and ignored.
| Property | Use and ownership | Declared type | Initial value |
|---|---|---|---|
label | Provides the visible label and accessible name for the component. | string | '' |
description | Provides supporting text associated with the control or value. | string | '' |
error | Provides the current validation or operation error associated with the control. | string | '' |
required | Marks the control as required for validation and native accessibility semantics. | boolean | false |
disabled | Prevents user interaction while keeping the control and its current value visible. | boolean | false |
readOnly | Keeps the current value focusable and readable while preventing edits. | boolean | false |
name | Provides the stable form or action name used by the host to identify this control. | string | '' |
autocomplete | Passes an autocomplete purpose to the native input so browsers can offer an appropriate saved value. | string | 'off' |
locale | Selects locale-sensitive formatting and parsing behavior. | string | 'en-US' |
validationState | Controls the current idle, pending, valid, or invalid validation state. | AeliqoValidationState | 'idle' |
validator | Runs host-provided synchronous validation for a proposed input value. | AeliqoValidator<T> | undefined | undefined |
options | Supplies the complete bounded choice list, including stable values, labels, descriptions, and disabled states. | readonly AeliqoOption[] | [] |
optionsLoader | Loads bounded combobox options for the current query. The host owns cancellation, authorization, and failures. | AeliqoOptionsLoader | undefined | undefined |
value | Controls the current value. Apply accepted user proposals back to this property. | string | '' |
defaultValue | Provides the initial uncontrolled value. Later updates come from component interaction. | string | '' |
query | Supplies the current search or combobox query independently from a committed selection. | string | '' |
placeholder | Provides a short input hint when the current draft is empty; it does not replace a visible label. | string | '' |
open | Controls whether the overlay or expandable surface is currently open. | boolean | false |
minQueryLength | Sets the number of query characters required before a combobox query proposal is useful. | number | 0 |
Events#
| Event | Payload | Emitted | Application responsibility |
|---|---|---|---|
aeliqo-input-change | {source, value, composing?} | Whenever the user proposes a draft value change. | Validate or store the draft and reassign controlled value or checked state. |
aeliqo-combobox-query | {source, query} | While the user edits the combobox query. | Cancel obsolete loads, fetch authorized bounded options, and update options. |
aeliqo-validation | {source, state, message} | When validation enters pending, valid, or invalid state. | Merge the result with application validation and display authoritative errors. |
Events cross the component boundary as user proposals. Validate their detail and current authority before applying a business effect.
Listen for aeliqo-input-change
const element = document.querySelector('aeliqo-combobox');<p>element?.addEventListener('aeliqo-input-change', (event) => {
const proposal = (event as CustomEvent<unknown>).detail;
// Validate the proposal, update host state, then assign controlled properties.
applyProposal(proposal);
});Listen for aeliqo-combobox-query
const element = document.querySelector('aeliqo-combobox');</p>
<p>element?.addEventListener('aeliqo-combobox-query', (event) => {
const proposal = (event as CustomEvent<unknown>).detail;
// Validate the proposal, update host state, then assign controlled properties.
applyProposal(proposal);
});Listen for aeliqo-validation
const element = document.querySelector('aeliqo-combobox');</p>
<p>element?.addEventListener('aeliqo-validation', (event) => {
const proposal = (event as CustomEvent<unknown>).detail;
// Validate the proposal, update host state, then assign controlled properties.
applyProposal(proposal);
});States and failure handling#
Relevant states:
- ready
- disabled
- invalid
- pending
- error
Expected result: The query and selected identity remain distinct while the list stays bounded.
Changing value or replacing validator cancels validation for the
previous value and clears its validator-owned error. An independently supplied
host error survives the change. Late results after a reset or disconnect are
ignored.
With a static options array, the component filters the bounded list as the
query changes. optionsLoader(query, signal) is the optional remote path: the
host owns the request and its authorization, while the component aborts the
previous load and ignores an older completion. At most 500 options are
accepted. A loader failure keeps the field visible, reports “Options could
not be loaded”, and never commits a different value. minQueryLength delays
loading until enough characters are typed.
Keyboard, focus, and accessibility#
Keyboard behavior:
- Tab
- Arrow keys
- Enter
- Escape
- IME composition
Exposed semantics:
- aria-activedescendant
- aria-autocomplete
- aria-controls
- aria-describedby
- aria-disabled
- aria-expanded
- aria-invalid
- aria-selected
- input
- li
- role
- ul
Responsive behavior#
Keep the query draft and selected value distinct at narrow widths. Test long option names against the visible viewport.
Style hooks#
- Shadow parts:
description,error,field,input,label,listbox,option,pending,status - Varendo design tokens referenced:
--aeliqo-color-accent,--aeliqo-color-border,--aeliqo-color-canvas,--aeliqo-color-muted,--aeliqo-color-surface,--aeliqo-control-min-target,--aeliqo-elevation-lg,--aeliqo-radius-medium,--aeliqo-radius-small,--aeliqo-space-10,--aeliqo-space-32,--aeliqo-space-6
Performance limits#
- The source-defined `COMBOBOX_MAX_OPTIONS` limit is 500.
Related components#
Generated TypeScript declaration#
View generated declaration
export declare class AeliqoComboboxElement extends AeliqoFieldElement<string> {
static readonly properties: {
label: {
type: StringConstructor;
};
description: {
type: StringConstructor;
};
error: {
type: StringConstructor;
};
required: {
type: BooleanConstructor;
reflect: boolean;
};
disabled: {
type: BooleanConstructor;
reflect: boolean;
};
readOnly: {
attribute: string;
type: BooleanConstructor;
reflect: boolean;
};
name: {
type: StringConstructor;
reflect: boolean;
};
autocomplete: {
type: StringConstructor;
};
locale: {
type: StringConstructor;
};
validationState: {
attribute: string;
type: StringConstructor;
reflect: boolean;
};
validator: {
attribute: boolean;
};
options: {
attribute: boolean;
};
optionsLoader: {
attribute: boolean;
};
value: {
type: StringConstructor;
reflect: boolean;
};
defaultValue: {
attribute: string;
type: StringConstructor;
};
query: {
type: StringConstructor;
};
placeholder: {
type: StringConstructor;
};
open: {
type: BooleanConstructor;
reflect: boolean;
};
minQueryLength: {
attribute: string;
type: NumberConstructor;
};
};
options: readonly AeliqoOption[];
optionsLoader: AeliqoOptionsLoader | undefined;
value: string;
defaultValue: string;
query: string;
placeholder: string;
open: boolean;
minQueryLength: number;
private activeIndex;
private loadSequence;
private loadAbort;
private composing;
private suppressTrailingCompositionInput;
connectedCallback(): void;
protected willUpdate(changed: Map<PropertyKey, unknown>): void;
protected updated(changed: Map<PropertyKey, unknown>): void;
protected isCurrentValidationValue(value: string): boolean;
disconnectedCallback(): void;
protected resetField(): void;
protected render(): import("lit").TemplateResult<1>;
private activeOptionId;
private isInvalidSelection;
private renderOptionList;
private renderOption;
focus(options?: FocusOptions): void;
get loading(): boolean;
private readonly handleFocus;
private readonly handleBlur;
private readonly handleInput;
private readonly handleKeyDown;
private handleArrowKey;
private handleEscapeKey;
private handleEnterKey;
private choose;
private readonly handleCompositionStart;
private readonly handleCompositionEnd;
private commitQueryInput;
private loadForQuery;
private safeOptions;
private filteredOptions;
private labelForValue;
private displayQuery;
private firstEnabledIndex;
private nextEnabledIndex;
private navigationStart;
private native;
private syncNative;
private cancelLoader;
static readonly styles: import("lit").CSSResult[];
}Version#
This page documents the Varendo 0.6 component contract.
