@llselect/core
The package entry: the two select classes, their settings types, and the
SVG icon builders. Language packs live in @llselect/core/i18n.
Select classes
abstract LLSelectBase
Defined in: base.ts:868
Abstract base for all select variants. Owns DOM scaffolding, ARIA wiring,
positioning, keyboard navigation, lazy popup-list rendering, and
outside-click handling. Subclasses (LLSelectSingle, LLSelectMultiple)
own chosen-state, decide what happens on item click, and customise the
trigger text via renderTriggerContent.
Extended by
Type Parameters
| Type Parameter | Default type | Description |
|---|---|---|
T |
unknown |
item value type. Use unknown (default) only when you intend to narrow inside templates / handlers; usually pass a concrete type like string or your domain object. |
GroupKey |
string |
the group key type itemToGroupKeyFn returns (null from that fn means "this item is in no group"). Defaults to string. Open it to objects only together with groupKeyCompareFn; see DESIGN.md "Data model". |
S extends LLSelectBaseSettings<T, GroupKey> |
LLSelectBaseSettings<T, GroupKey> |
the resolved settings type, for subclasses that EXTEND the settings bag. Plain use never passes it. A subclass declares extends LLSelectBase<T, GroupKey, MySettings> and this.settings is typed MySettings; the constructor's subclassSettings param then only accepts exactly the extra fields. |
Items
getItems()
getItems(): readonly
T[]
Defined in: base.ts:1582
Return the current item list, in data order (as passed to setItems).
- The rendered list may differ in order and content: see
getVisibleItems. - Returns the LIVE internal array, typed read-only. Do not mutate it (TS blocks it; plain-JS callers must treat it as frozen).
- Structural mutation would silently bypass chosen-state reconciliation,
re-filtering, and re-render. Replace the list via
setItemsinstead. - Mutating item OBJECTS +
rerender()is the supported in-place path.
Returns
readonly T[]
setItems()
setItems(
items):void
Defined in: base.ts:1670
Replace the item list.
- The input is shallow-copied; later external mutation does not affect the select.
- Items MUST be unique under
compareFn(it defines item identity, and the selection is a set). Duplicates render stale selection DOM; the default compareFn warns once per page, a custom compareFn is the caller's responsibility (not scanned, to keep large lists cheap). - If the popup is open, it re-renders now. While closed, the DOM is
built lazily on the next
open(). - Both shipped variants re-render the trigger content from
onItemsChanged(the multiple count total, custom content that readsitems). LLSelectMultiple'striggerDisplay: 'tags'mode is opt-in;'count'is the default.- When
triggerDisplayis'tags', that content render is one chip per chosen item, unlesscreateTriggerContentElFnreplaces the content. - Subclasses may reconcile chosen-state via onItemsChanged (e.g. single mode drops a chosen value that is no longer in the list).
Parameters
| Parameter | Type |
|---|---|
items |
readonly T[] |
Returns
void
getVisibleItems()
getVisibleItems(): readonly
T[]
Defined in: base.ts:3241
Return the items the popup list renders, in display order.
items (setItems)
| gather (only with grouping on; result cached until setItems)
v
display base list
| filter query (only while a query is active)
v
visible items (this method's return value)
| render
v
DOM rows
- If no filter query is active (including while closed), it returns the
full list, gathered per
gatherGroupswhen grouping is on. - If a filter query is active, it returns the matching subset.
- Disabled items are included. They render (grayed); only actions skip them (keyboard focus, the choose-all row's subset).
- Returns the LIVE internal array, typed read-only. Never mutate it
(see
getItems). - Subclasses use it too (e.g. for selection-by-index), and may override
it to add a step:
LLSelectMultipledoes forhideChosenRows.
Returns
readonly T[]
Open & close
open()
open():
void
Defined in: base.ts:1363
Open the popup. Builds item elements lazily, attaches the positioner (which auto-closes if the trigger is scrolled out of view), wires the outside-click handler, and moves keyboard focus into the item list. No-op if already open.
Returns
void
close()
close():
void
Defined in: base.ts:1447
Close the popup. Detaches positioner and outside-click listener, clears the item DOM, and resets focused-item state. No-op if already closed.
Focus return is decided automatically: when DOM focus is still inside
the popup at the moment of close - the filter input (Esc on an empty
filter, a single-select pick, an outside press on a non-focusable area)
or a focusable control the app placed in a header / footer slot (Esc
there, or close() called from its own click) - focus is returned to
the trigger. Tab-away and outside clicks on focusable elements have
already moved focus elsewhere, so we leave it alone.
Returns
void
toggle()
toggle():
void
Defined in: base.ts:1552
Open if closed, close if open.
Returns
void
isOpened()
isOpened():
boolean
Defined in: base.ts:1568
Whether the popup is currently open.
- Pairs with
isDisabled()(state read via method). - The same state is mirrored on the DOM as CSS hooks:
data-state="open|closed"on the trigger,classIdMap.openClasson the root.
Returns
boolean
Trigger
setPlaceholder()
setPlaceholder(
placeholder):void
Defined in: base.ts:1643
Replace the trigger placeholder text at runtime. It is one of the two
settings with a runtime setter (the other is setUiTranslationPack);
both are copy. The rule: LLSelectBaseSettings.
null= fall back to the pack default (uiTranslationPack.triggerPlaceholder), mirroring an unset constructorplaceholder. An explicit value keeps winning over latersetUiTranslationPackcalls, exactly like the constructor input.- Takes effect immediately. Visible only while nothing is chosen - the placeholder never renders otherwise (the trigger is still re-rendered, which also refreshes the hidden accessible-value mirror).
Parameters
| Parameter | Type |
|---|---|
placeholder |
string | null |
Returns
void
Filtering
getFilterQuery()
getFilterQuery():
string
Defined in: base.ts:3271
Return the filter input's current query, exactly the string passed to
filterFn.
- It is
''while the popup is closed, the filter is inactive, or the input is empty. - It resets on close: each open cycle starts empty.
Returns
string
Disabling
setDisabled()
setDisabled(
value):void
Defined in: base.ts:1706
Enable or disable the whole control. Disabled: the trigger gets
aria-disabled + data-disabled (never the native disabled attribute,
which would suppress the hover / focus events a tooltip needs), opening is
blocked, an open popup closes, and the trigger leaves the tab order unless
focusableWhenDisabled is set. Stored as state, mirroring setItems /
setChosenItems (this design keeps mutable state out of settings).
Parameters
| Parameter | Type |
|---|---|
value |
boolean |
Returns
void
isDisabled()
isDisabled():
boolean
Defined in: base.ts:1717
Whether the whole control is disabled.
Returns
boolean
i18n
getUiTranslationPack()
getUiTranslationPack():
Readonly<LLSelectUiTranslationPack>
Defined in: base.ts:1595
Return the resolved UI strings: the built-in English defaults merged
with the uiTranslationPack setting.
- Reuse these in your own UI instead of keeping a second translation
source. For example, a tag remove button tooltip:
sel.getUiTranslationPack().tagRemoveButtonAriaLabel(label). - Returns the LIVE object. Treat it as immutable, like
getItems.
Returns
Readonly<LLSelectUiTranslationPack>
setUiTranslationPack()
setUiTranslationPack(
uiTranslationPack):void
Defined in: base.ts:1616
Replace the UI-translation pack at runtime, so switching language needs
no re-new.
- One of the two settings with a runtime setter (the other is
setPlaceholder); both are copy. The rule: LLSelectBaseSettings. - The pack is resolved exactly like the constructor's: merged over the built-in English pack, NOT over the previously set pack.
- An explicit constructor
placeholderkeeps winning over the new pack'striggerPlaceholder. - Re-renders the trigger and the open popup.
- Also re-applies the pack-owned attributes
rerender()cannot reach: the filter input placeholder and its fallbackaria-label. - The clear button needs no such step:
rerender()rebuilds it, and the rebuild reads the new pack - unless acreateTriggerClearButtonEloverride returns the previous element, which then owns the label.
Parameters
| Parameter | Type |
|---|---|
uiTranslationPack |
Partial<LLSelectUiTranslationPack> |
Returns
void
Lifecycle
Constructor
new LLSelectBase<
T,GroupKey,S>(targetEl,settings?,subclassSettings?):LLSelectBase<T,GroupKey,S>
Defined in: base.ts:1098
Parameters
| Parameter | Type | Description |
|---|---|---|
targetEl |
HTMLElement |
mount element. Becomes rootEl; its existing children are wiped and replaced with the trigger + popup structure. Pre-set classes / id / data-* attributes on this element are preserved. |
settings? |
LLSelectSettingsInputOf<S> |
optional partial settings. Missing fields use defaults (LLSelectBaseSettings). |
subclassSettings? |
Omit<S, keyof LLSelectBaseSettings<T, GroupKey>> |
for subclasses that EXTEND the settings bag: their own fields, already resolved (defaults applied). Typed by the class's S param, so it accepts exactly the extra fields and nothing else. Merged into this.settings right here, so the bag is complete before any base construction code (e.g. createFilterInputEl reading the pack) can read it. |
Returns
LLSelectBase<T, GroupKey, S>
rerender()
rerender():
void
Defined in: base.ts:1517
Rebuild the trigger and (while open) the popup list from current state.
- Use it after mutating item OBJECTS in place (e.g.
users[0].name = 'X'). The library cannot detect that on its own. - It re-derives the display order (the
gatherGroupsgather). - While the filter is active, it re-runs the filter against the current item text.
- The refresh is purely visual: it does NOT fire
onChangeand does NOT runonItemsChanged. - Orchestrator: composes
renderTrigger+renderPopupList; touches no DOM directly.
Returns
void
destroy()
destroy():
void
Defined in: base.ts:1537
Tear down the instance: close the popup (which detaches every document /
window listener and the positioner), unwire labelEl (click listener
removed, a minted id removed), remove the library's class and
inline styles from the caller's mount element, and empty it. Idempotent.
The instance must not be used afterwards.
- REQUIRED before discarding an instance that might be OPEN (framework wrappers: call this on unmount) - skipping it there leaks the outside-click / focusout / scroll / resize listeners.
- Discarding a CLOSED instance without
destroy()leaks nothing; it only leaves the root class andoverflow-anchorstyle on the mount.
Returns
void
DOM elements
rootEl
readonlyrootEl:HTMLElement
Defined in: base.ts:875
The caller-passed mount element, now decorated as the select's root. Library does not replace this node, so the caller's original reference, id, and data-* attributes stay valid.
triggerEl
readonlytriggerEl:HTMLElement
Defined in: base.ts:885
The interactive trigger element. Receives focus, click, and keydown
events; carries aria-expanded, aria-controls, and
data-state="open|closed". Its role depends on the filter mode: combobox
while the filter is inactive (it then also hosts aria-activedescendant) and
button while a filterable popup is open (the filter input hosts
aria-activedescendant). See docs/llm/A11Y.md.
triggerContentEl
readonlytriggerContentEl:HTMLElement
Defined in: base.ts:892
Inner span inside the trigger where text/tags are written.
Subclasses' renderTriggerContent writes here so the sibling arrow slot
is preserved across re-renders.
popupEl
readonlypopupEl:HTMLElement
Defined in: base.ts:909
The outer popup wrapper. Has no ARIA role itself - it just hosts the
popup chrome (future: filter input, toggle-all control) and the inner
popupListEl. Hidden via the hidden attribute when closed; positioned
via inline styles by the positioner when open.
popupListEl
readonlypopupListEl:HTMLElement
Defined in: base.ts:917
The inner element with role="listbox", holding the item children.
Sits inside popupEl so siblings (filter input, toggle-all) can live
above it without violating ARIA's "listbox children must be options"
rule. The trigger's aria-controls points to this element.
popupHeaderEl
readonlypopupHeaderEl:HTMLElement|null
Defined in: base.ts:925
The pinned header container between the filter input and the listbox,
or null when no header content was built. No ARIA role; outside the
scroll area. Built once in the constructor (createPopupHeaderEl) and
kept until destroy(); the library never rebuilds or moves it.
popupFooterEl
readonlypopupFooterEl:HTMLElement|null
Defined in: base.ts:932
The pinned footer container at the bottom of the popup, after the
no-results message, or null when no footer content was built. Same
lifecycle as popupHeaderEl.
popupListPinnedLeadingRowsEl
readonlypopupListPinnedLeadingRowsEl:HTMLElement|null
Defined in: base.ts:950
The wrapper around the pinned leading rows, or null.
- Built once in the constructor when
popupListLeadingRowsPinnedistrue;nullotherwise. - A
divwithrole="presentation"and classpopupListPinnedLeadingRowsClass; the library setsposition: stickyandtop: 0on it inline. - In the listbox only while the leading rows exist. The library moves it
in and out on every list render. Its classes are yours to change after
new. data-edge-to-itemsis set on every list render:"true"when that render lists items,"false"when it lists none; absent before the first render.- It is a CSS hook for the themes: they draw the block's edge line only when it is true, so two blocks that touch draw no line between them.
popupListPinnedTrailingRowsEl
readonlypopupListPinnedTrailingRowsEl:HTMLElement|null
Defined in: base.ts:957
The wrapper around the pinned trailing rows, or null.
- Same contract as popupListPinnedLeadingRowsEl, for
popupListTrailingRowsPinned, withbottom: 0.
classIdMap
readonlyclassIdMap:LLSelectClassIdMap
Defined in: base.ts:962
Resolved class names and ids for this instance.
triggerValueEl
protectedreadonlytriggerValueEl:HTMLElement
Defined in: base.ts:901
Hidden root-level span (sibling of the trigger) mirroring the current
value as plain text. Kept in sync by commitTriggerContentToDom;
referenced by the filterable-mode aria-labelledby chain (see
classIdMap.triggerValueId). Outside the trigger so
triggerEl.textContent stays exactly the visible content.
Subclassing: reactions
onOpened()
protectedonOpened():void
Defined in: base.ts:1753
Subclass hook: called once after the popup finishes opening. Default no-op.
The onOpen setting fires alongside this (both run) - hook for subclass
logic, setting for consumer notification.
Returns
void
onClosed()
protectedonClosed():void
Defined in: base.ts:1758
Subclass hook: called once after the popup finishes closing. Pairs with the onClose setting (both run).
Returns
void
onChosenChanged()
protectedonChosenChanged():void
Defined in: base.ts:1765
Subclass hook: called after the chosen state actually changed, right
before the variant's onChange setting fires (hook first, both run -
same pairing as onOpened / onClosed). Default no-op.
Returns
void
onItemsChanged()
protectedonItemsChanged():void
Defined in: base.ts:1772
Called after setItems finishes. Override to reconcile state that
depends on the item list (e.g. clear a chosen value that disappeared).
Default no-op.
Returns
void
onItemActivated()
protectedonItemActivated(_item):void
Defined in: base.ts:2399
Called when an item is activated (click or keyboard select). Default no-op; subclasses implement their selection behaviour (single mode picks and closes, multiple mode toggles and keeps the popup open).
Parameters
| Parameter | Type |
|---|---|
_item |
T |
Returns
void
onPopupListActionRowActivated()
protectedonPopupListActionRowActivated(row):void
Defined in: base.ts:2522
Subclass hook: an action row was activated.
- The library calls it on Enter, on Space while the filter is inactive,
and on click, after the disabled re-check, as a user change. You never
call it.
rowcomes from the library: the activated entry. - Default calls the entry's
onActivate. The library changes nothing else: choosing and closing are the entry's job. - Override to react before or after: do your work, then call
super.onPopupListActionRowActivated(row). Without that call the entry'sonActivatenever runs.
Parameters
| Parameter | Type |
|---|---|
row |
LLSelectPopupListActionRow |
Returns
void
withUserChangeSource()
protectedwithUserChangeSource<R>(fn):R
Defined in: base.ts:2582
Run fn with chosen-state changes attributed to the user. The library
wraps exactly its pointer / keyboard entry points with it - option
activation, the tag remove button, the clear button, the choose-all row;
everything else reports 'api'.
Type Parameters
| Type Parameter |
|---|
R |
Parameters
| Parameter | Type |
|---|---|
fn |
() => R |
Returns
R
onChooseAllRowActivated()
protectedonChooseAllRowActivated():void
Defined in: base.ts:2597
Subclass hook: the choose-all row was activated - Enter while it is focused (subclasses also wire their row's click handler to this). Default no-op.
Returns
void
Subclassing: rendering
renderTrigger()
protectedrenderTrigger():void
Defined in: base.ts:1810
Orchestrator: composes the clear-button rebuild + renderTriggerContent +
renderTriggerArrow to (re)build the whole trigger from state; touches no
DOM directly. Subclasses normally override renderTriggerContent,
not this.
- Runs on every change of the chosen value, the placeholder or the pack.
rerender()runs it too.- While
clearableis on, the first run builds the clear button and every later run swaps it for whatevercreateTriggerClearButtonElreturns: a fresh button from the base implementation, like the arrow. An override may return the previous element; it is then kept in place. - If the button is rebuilt and the old one held focus - on it or inside its icon - the rebuilt BUTTON gets it.
- If the builder returned the same element, nothing was rebuilt, and focus goes back to the node that held it, if that node is still inside the button and can take focus; otherwise focus stays on the button.
setItemsrunsrenderTriggerContentalone, because only the content reads the list (the multiple count total, a customcreateTriggerContentElFn'sitems).- A
setItemsthat drops the chosen entry runs the whole trigger. - Runs once from the
LLSelectSingle/LLSelectMultipleconstructor, right aftersuper(). - On that first run a FURTHER subclass's own fields are still
undefined: JS runs a subclass's field initializers only after its super constructor returns (virtual-call-in-constructor). An override of a trigger method (renderTriggerContent, or acreate*Elit calls) that reads such a field seesundefinedthere. - The recipe: put construction-time configuration in the typed
subclassSettingsconstructor param.this.settingsis complete before any construction code runs. - For genuine instance state, tolerate defaults during construction, or call
rerender()at the end of your own constructor. - The popup-list methods do NOT run here; they wait for
open(). See DESIGN.md "Customization model".
Returns
void
commitTriggerContentToDom()
protectedcommitTriggerContentToDom(content,plainTextValue?):void
Defined in: base.ts:1833
Write the trigger's content slot (triggerContentEl), replacing whatever
was there; the sibling arrow slot is untouched. The single DOM-writing
primitive behind every renderTriggerContent path.
string-> set astextContent(plain text, NOT parsed as HTML). Used for the default placeholder /itemToStringtext / count summary.HTMLElement-> inserted as-is viareplaceChildren; caller owns the node. Used for whatever thecreateTriggerContentElFnsetting returned.- Also mirrors the value into the hidden
triggerValueEl(the accessible name source): the string itself, elseplainTextValue, else the element'stextContent. PassplainTextValuewhenever the element contains labelled controls (tag remove buttons) or icon-only content - the mirror is what AT announces as the field's value. Called byrenderTriggerContent- the base default and theLLSelectSingle/LLSelectMultipleoverrides.
Parameters
| Parameter | Type |
|---|---|
content |
string | HTMLElement |
plainTextValue? |
string |
Returns
void
syncEmptyStateToDom()
protectedsyncEmptyStateToDom():void
Defined in: base.ts:1850
Mirror the empty/filled state onto the trigger's data-empty attribute
("true" when isEmpty(), else "false"). A CSS / AT styling hook,
independent of the rendered content. Called by the subclass
renderTriggerContent overrides.
Returns
void
renderTriggerContent()
protectedrenderTriggerContent():void
Defined in: base.ts:1873
Orchestrator: composes the *ToDom primitives to (re)build the trigger's
content slot from state; touches no DOM directly. Override in subclasses to
display the chosen value(s); this base default commits the placeholder and
the empty flag. Always write via commitTriggerContentToDom (content) and
syncEmptyStateToDom (the data-empty flag), never triggerContentEl
directly, so the sibling arrow slot is always preserved.
Returns
void
createTriggerArrowContentEl()
protectedcreateTriggerArrowContentEl(state):HTMLElement|SVGElement|null
Defined in: base.ts:1896
Trigger arrow element for the given open state.
- Default reads
createTriggerArrowContentElFn;null(setting unset, or returned for a state) = no arrow for that state. - Override only when extending; for one-off arrows pass the setting.
Mirrors
createTriggerClearButtonEl/createItemContentEl.
Parameters
| Parameter | Type |
|---|---|
state |
{ isOpened: boolean; } |
state.isOpened |
boolean |
Returns
HTMLElement | SVGElement | null
renderPopupList()
protectedrenderPopupList():void
Defined in: base.ts:1929
Orchestrator: composes createItemEl (build) + computePopupSegments +
commitPopupSegmentsToDom (write) to rebuild the popup list from
getVisibleItems(); touches no DOM directly. Called by open() and by
setItems() while open. Also clamps focusedIndex if the list shrank and
re-applies focus visuals.
- Extend it by wrapping: override, do your work before or after, then
call
super.renderPopupList(). The ui-select bridge frees its row scopes this way. Or override one of the methods it calls throughthis:createItemEl,createPopupListChooseAllRowEl,createPopupListLeadingActionRowEl/createPopupListTrailingActionRowEl,itemToGroupKey,getVisibleItems. - Its other internals stay private on purpose. They re-establish the
itemEls[i] <-> getVisibleItems()[i]alignment as one unit, so no subclass can leave keyboard nav oraria-activedescendanthalf-synced.
Returns
void
createGroupEl()
protectedcreateGroupEl(key,index,items,itemEls):HTMLElement
Defined in: base.ts:2064
Build the whole DOM element for one group container.
- The library calls it, once per group of the current render, on every list render. You never call it yourself.
- All four params come from the library. Forward them to
superunchanged. indexis the group's position among this render's groups, counted from 0. It only mints the group id. It is not an identity: it changes whenever the visible list changes.- To change only the label's content, do not override this. Pass the
createGroupLabelContentElFnsetting instead. - To change the element itself, override it, call
super.createGroupEl(...), and edit the returned element. Keep theroleandaria-labelthe base set. - Internals: the base sets the id,
role="group"named bygroupKeyToString(aria-label), anaria-hiddenvisible label element filled from createGroupLabelContentEl (else the plain label text), then the group's item elements;aria-disabled+data-disabledwhen the group is disabled.
Parameters
| Parameter | Type | Description |
|---|---|---|
key |
GroupKey |
the group's key, supplied by the library |
index |
number |
the group's position among this render's groups, supplied by the library |
items |
readonly T[] |
the group's items, supplied by the library (for counts / rich content) |
itemEls |
HTMLElement[] |
the group's already-built option elements, supplied by the library |
Returns
HTMLElement
createGroupLabelContentEl()
protectedcreateGroupLabelContentEl(key,itemsInGroup):HTMLElement|null
Defined in: base.ts:2098
Group label -> its visible content element (icon / count badge / rich
markup). Mirrors createItemContentEl.
- Default reads
createGroupLabelContentElFn, elsenullsocreateGroupEluses plain text fromgroupKeyToString. - The group's accessible name stays
groupKeyToString(containeraria-label); this fills only the visible,aria-hiddenlabel content. - Override only when extending; for one-off rich labels pass the setting.
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
itemsInGroup |
readonly T[] |
Returns
HTMLElement | null
replacePopupListItemElInDom()
protectedreplacePopupListItemElInDom(item):void
Defined in: base.ts:2112
Re-render a single item's element in place instead of rebuilding the whole popup list. The DOM work is O(1) regardless of list size, so flipping one selection in a 10k-item list does not recreate 10k nodes (the lookup to find the item is O(n), but that is a cheap comparison loop next to DOM mutation). No-op if the popup is closed or the item is not in the current list. Used by multi-select toggle.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
void
createItemEl()
protectedcreateItemEl(item,index):HTMLElement
Defined in: base.ts:2161
Build the whole DOM element for one option row.
- The library calls it, once per row of
getVisibleItems(), on every list render. You never call it yourself. - Both params come from the library. Forward them to
superunchanged. itemis the row's item.indexis the row's position ingetVisibleItems(), counted from 0. That is the list as rendered: grouped, filtered, minus hidden chosen rows. It is NOT the position initems.indexis not an identity. It changes whenever the visible list changes. Item identity iscompareFn. Never store it.- To change only what a row shows, do not override this. Pass the
createItemContentElFnsetting instead. - To change the element itself, override it, call
super.createItemEl(item, index), and edit the returned element: add a class, atitle, a wrapper. Demo sections 9.1, 13.1 and 13.2 do this. - Keep the
idandrolethe base set. Do not put focusable controls inside the row. The row itself is the control. - The element is rebuilt on every render. Do not keep a reference to it.
- Internals: the base sets
id(<listbox id>-item<index>, the target ofaria-activedescendant),role="option", the visible content from createItemContentEl (elsetextContentfrom itemToString),aria-label=itemToStringwhen the content is custom,aria-disabledplus the disabled class when isItemEffectivelyDisabled, and a click handler that focuses the row byindex, then runsonItemActivated.
Parameters
| Parameter | Type | Description |
|---|---|---|
item |
T |
the row's item, supplied by the library |
index |
number |
the row's position in getVisibleItems(), supplied by the library |
Returns
HTMLElement
createItemContentEl()
protectedcreateItemContentEl(item):HTMLElement|null
Defined in: base.ts:2222
Item -> the visible content of its list row (icon + text etc.).
- Default reads
createItemContentElFn, elsenullsocreateItemEluses the plain-text default fromitemToString. - Override only when extending; for one-off rich content pass the setting.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
HTMLElement | null
createPopupListLeadingActionRowEl()
protectedcreatePopupListLeadingActionRowEl(row,index):HTMLElement
Defined in: base.ts:2427
Build the whole DOM element for one leading action row (above the items).
- The library calls it, once per entry of
popupListLeadingActionRows, on every list render and after every chosen change. You never call it. - Both params come from the library. Forward them to
superunchanged.rowis the entry;indexis its position in that array, counted from 0, used to mint the id. It is not an identity. - To change only what the row shows, do not override this: give the entry
a
createContentElFn. - To change the element itself, override it, call
super.createPopupListLeadingActionRowEl(row, index), and edit the returned element. Keep theidandrole; put no focusable control inside. - Internals: a
divwithrole="option", the id<listbox id>-action-row-leading<index>,itemClasspluspopupListActionRowClass, the visible content from createPopupListActionRowContentEl (elsetextContentfromtextFn),aria-label=textFn()when the content is custom, and eitheraria-disabledplus the disabled class (isPopupListActionRowDisabled) or a click handler that focuses the row, then runs onPopupListActionRowActivated. Noaria-selected: a command has no selected state.
Parameters
| Parameter | Type | Description |
|---|---|---|
row |
LLSelectPopupListActionRow |
the entry, supplied by the library |
index |
number |
the entry's position in popupListLeadingActionRows, supplied by the library |
Returns
HTMLElement
createPopupListTrailingActionRowEl()
protectedcreatePopupListTrailingActionRowEl(row,index):HTMLElement
Defined in: base.ts:2450
Build the whole DOM element for one trailing action row (below the items).
- The library calls it, once per entry of
popupListTrailingActionRows, on every list render and after every chosen change. You never call it. - Both params come from the library. Forward them to
superunchanged.rowis the entry;indexis its position in that array, counted from 0, used to mint the id. It is not an identity. - To change only what the row shows, do not override this: give the entry
a
createContentElFn. - To change the element itself, override it, call
super.createPopupListTrailingActionRowEl(row, index), and edit the returned element. Keep theidandrole; put no focusable control inside. - Internals: identical to createPopupListLeadingActionRowEl
except the id,
<listbox id>-action-row-trailing<index>.
Parameters
| Parameter | Type | Description |
|---|---|---|
row |
LLSelectPopupListActionRow |
the entry, supplied by the library |
index |
number |
the entry's position in popupListTrailingActionRows, supplied by the library |
Returns
HTMLElement
createPopupListActionRowContentEl()
protectedcreatePopupListActionRowContentEl(row):HTMLElement|null
Defined in: base.ts:2493
An action row's visible content element.
- The library calls it from the row builders, once per row render. You
never call it.
rowcomes from the library. - Default reads the entry's
createContentElFn;null(unset, or returned) = plain text fromtextFn. - Override only when extending; for one-off content give the entry a
createContentElFn.
Parameters
| Parameter | Type |
|---|---|
row |
LLSelectPopupListActionRow |
Returns
HTMLElement | null
replacePopupListActionRowElsInDom()
protectedreplacePopupListActionRowElsInDom():void
Defined in: base.ts:2538
Rebuild every rendered action row in place, so textFn / disabledFn
reflect the current state; the row holding the active option keeps it.
- The library calls it after every chosen change, right after
onChangefired (a row's text may read what the handler wrote). Subclasses may call it after a state change of their own. - No-op while closed, or when both row arrays are empty - instances without rows pay nothing.
- O(rows) DOM work; the item rows are untouched.
Returns
void
createPopupListChooseAllRowEl()
protectedcreatePopupListChooseAllRowEl():HTMLElement|null
Defined in: base.ts:2573
Optional non-item role="option" row placed first, at the TOP of the listbox:
inside the arrow-key ring (ArrowUp from the first item reaches it, Home
lands on it, up-actions clamp there) but never inside itemEls, so the
itemEls[i] <-> getVisibleItems()[i] alignment is untouched. Rebuilt on
every renderPopupList. Base default: null = no choose-all row.
LLSelectMultiple builds its choose-all row here (chooseAllRow setting).
Returns
HTMLElement | null
replaceChooseAllRowElInDom()
protectedreplaceChooseAllRowElInDom():void
Defined in: base.ts:2652
Rebuild the choose-all row in place (tri-state / text refresh) without
touching the item elements - O(1) DOM work, mirroring
replacePopupListItemElInDom. Falls back to a full renderPopupList
when the row becomes inapplicable (builder returns null). No-op while
closed or when no choose-all row is rendered.
Returns
void
createTriggerClearButtonEl()
protectedcreateTriggerClearButtonEl():HTMLElement
Defined in: base.ts:3047
Build the clear (x) button for the clearable trigger slot.
- The library owns the button, its click (stops propagation so it never
toggles the popup, then
clearSelection; a no-op while the control is disabled) and itsaria-label(text fromuiTranslationPack.triggerClearButtonAriaLabel). createTriggerClearButtonContentElFnoptionally fills the icon; else the theme's CSS glyph draws it.- The theme hides the button via
data-emptywhile nothing is chosen. - It runs on every trigger render (
renderTrigger). - The first run builds the button.
- For
LLSelectSingle/LLSelectMultipleand their subclasses, that first run is the variant constructor's render, right aftersuper(), so it happens before a FURTHER subclass's field initializers. - A direct
LLSelectBasesubclass gets the button on its first trigger render (its ownrenderTrigger()call, orrerender()/setPlaceholder); until then the trigger is unrendered and there is no button. - Every later run (a value change,
setPlaceholder,setUiTranslationPack,rerender()) swaps the button in place, unless this method returns the previous element - then it stays in place. - The base implementation returns a fresh element each run, so, like the arrow, nothing put on it from outside survives a render; customize it here.
- An override that returns the same element every time owns everything
the rebuild would otherwise refresh on it, including its
aria-labelaftersetUiTranslationPack. - An override that reads subclass fields calls
rerender()at the end of its constructor, like every other trigger method.
Returns
HTMLElement
createTriggerClearButtonContentEl()
protectedcreateTriggerClearButtonContentEl():HTMLElement|SVGElement|null
Defined in: base.ts:3174
Clear button's visible content (its x icon).
- Default reads
createTriggerClearButtonContentElFn;null(setting unset, or returned) = no icon - the theme's CSS glyph draws the x. - Override only when extending; for one-off icons pass the setting.
Returns
HTMLElement | SVGElement | null
createPopupListNoResultsContentEl()
protectedcreatePopupListNoResultsContentEl(query):HTMLElement|null
Defined in: base.ts:3356
The no-results message's visible content (rich empty-state).
- Default reads
createPopupListNoResultsContentElFn;null(setting unset, or returned) = plain text fromuiTranslationPack.popupListNoResults. - Override only when extending; for one-off content pass the setting.
Parameters
| Parameter | Type |
|---|---|
query |
string |
Returns
HTMLElement | null
createPopupHeaderEl()
protectedcreatePopupHeaderEl():HTMLElement|null
Defined in: base.ts:3376
Build the pinned header container between the filter input and the listbox.
- The library calls it once, inside the constructor. You never call it.
- It takes no params. The default asks createPopupHeaderContentEl
for content;
nullcontent = no container, andpopupHeaderElstaysnull. - To supply content without subclassing, pass
createPopupHeaderContentElFn. - To change the container itself, override it: call
super.createPopupHeaderEl()and edit the returned element, or return your owndiv. Returning non-null builds the slot even without the setting. Keep it role-free: it is not part of the listbox. - Internals: the base builds a
divwithclassIdMap.popupHeaderClassand inlineflex: none(the popup is a flex column and only the listbox may flex), then appends the content.
Returns
HTMLElement | null
createPopupHeaderContentEl()
protectedcreatePopupHeaderContentEl():HTMLElement|null
Defined in: base.ts:3390
The pinned header's content element.
- The library calls it once, from createPopupHeaderEl, inside the constructor. You never call it.
- Default calls
createPopupHeaderContentElFnwith a LLSelectConstructionContext;null(setting unset, or returned) = no header at all. - Override only when extending; for one-off content pass the setting.
Returns
HTMLElement | null
createPopupFooterEl()
protectedcreatePopupFooterEl():HTMLElement|null
Defined in: base.ts:3410
Build the pinned footer container at the bottom of the popup.
- The library calls it once, inside the constructor. You never call it.
- It takes no params. The default asks createPopupFooterContentEl
for content;
nullcontent = no container, andpopupFooterElstaysnull. - To supply content without subclassing, pass
createPopupFooterContentElFn. - To change the container itself, override it: call
super.createPopupFooterEl()and edit the returned element, or return your owndiv. Returning non-null builds the slot even without the setting. Keep it role-free: it is not part of the listbox. - Internals: the base builds a
divwithclassIdMap.popupFooterClassand inlineflex: none(only the listbox may flex), then appends the content.
Returns
HTMLElement | null
createPopupFooterContentEl()
protectedcreatePopupFooterContentEl():HTMLElement|null
Defined in: base.ts:3424
The pinned footer's content element.
- The library calls it once, from createPopupFooterEl, inside the constructor. You never call it.
- Default calls
createPopupFooterContentElFnwith a LLSelectConstructionContext;null(setting unset, or returned) = no footer at all. - Override only when extending; for one-off content pass the setting.
Returns
HTMLElement | null
Subclassing: semantics
isEmpty()
protectedisEmpty():boolean
Defined in: base.ts:1860
Whether the control currently has no selection (drives data-empty).
Base default is always true (the base trigger only shows the
placeholder); LLSelectSingle / LLSelectMultiple override it.
Returns
boolean
itemToString()
protecteditemToString(item):string
Defined in: base.ts:2210
Map an item to its display string. The library calls this everywhere it needs an item's text: list rows, the single trigger text, default filter.
- Default reads the
itemToStringFnsetting, elseString(item). - Configure via
itemToStringFn(no subclass needed). - Override only when extending (a new select type); your override replaces
the default. For HTML content, subclass
createItemEl.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
string
isItemEffectivelyDisabled()
protectedisItemEffectivelyDisabled(item):boolean
Defined in: base.ts:2236
Whether item is effectively disabled - by itemDisabledFn, or because
its group is disabled (groupDisabledFn). Group-disabled layers on top,
so every item-disabled behavior (no selection, keyboard skip, aria)
covers grouped items with no extra code. False when neither applies.
The whole-control disabled state (isDisabled()) is a separate layer,
not part of this answer.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
boolean
itemToGroupKey()
protecteditemToGroupKey(item):GroupKey|null
Defined in: base.ts:2255
Map an item to its group key, or null when it belongs to no group.
The authoritative method: rendering, the gatherGroups gather, and the
disabled layer all resolve keys through this method, so an override
drives them all - returning keys turns grouping on even with the setting
unset (all-null keys = flat list). An override reading external state
must call rerender() after that state changes (same contract as
mutating item objects).
- Default reads
itemToGroupKeyFn, elsenull(grouping off). - Override only when extending; configure via the setting.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
GroupKey | null
groupKeyToString()
protectedgroupKeyToString(key):string
Defined in: base.ts:2265
Map a group key to its label display text.
- Default reads
groupKeyToStringFn, elseString(key).
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
Returns
string
isGroupDisabled()
protectedisGroupDisabled(key):boolean
Defined in: base.ts:2274
Whether the whole group key is disabled per groupDisabledFn (false when unset).
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
Returns
boolean
isPopupListActionRowDisabled()
protectedisPopupListActionRowDisabled(row):boolean
Defined in: base.ts:2505
Whether an action row is disabled right now.
- The library calls it from the row builders (once per row render) and
again at activation. You never call it.
rowcomes from the library. - Default reads the entry's
disabledFn;null/ omitted = never disabled.
Parameters
| Parameter | Type |
|---|---|
row |
LLSelectPopupListActionRow |
Returns
boolean
clearSelection()
protectedclearSelection():void
Defined in: base.ts:3187
Empty the selection (invoked by the clear button). Base is a no-op; single
clears to undefined, multiple to []. Goes through the normal setters, so
onChange fires with the empty value. The wipe is total - chosen disabled
items are cleared too (native <select> parity; unchooseAll is the
enabled-only bulk op).
Returns
void
matchesQuery()
protectedmatchesQuery(item,query):boolean
Defined in: base.ts:3283
Per-item match predicate for the filter input.
- Default reads
filterFn; else case-insensitive substring onitemToString. - Override only when extending (subclass-wide custom matching); for a one-off match rule pass the setting.
Parameters
| Parameter | Type |
|---|---|
item |
T |
query |
string |
Returns
boolean
Subclassing: focus
findNextEnabledIndex()
protectedfindNextEnabledIndex(start,step,list):number
Defined in: base.ts:2285
First enabled index scanning from start (inclusive) by step (+1 / -1).
Returns -1 if no enabled item lies in that direction. Used to skip disabled
items during keyboard nav and initial focus.
Parameters
| Parameter | Type |
|---|---|
start |
number |
step |
number |
list |
readonly T[] |
Returns
number
focusInitial()
protectedfocusInitial():void
Defined in: base.ts:2605
Decide which item to focus when the popup opens. Default focuses the first item (or no-op if the list is empty). Override to focus the currently chosen item, last-used item, etc.
Returns
void
setFocusedIndex()
protectedsetFocusedIndex(index):void
Defined in: base.ts:2617
Move keyboard focus to the item at index. The value is clamped to
[-1, items.length-1]; pass -1 to clear focus. Updates the focused
class, aria-activedescendant, and scrolls the item into view. No-op
if the clamped value equals the current focused index.
Parameters
| Parameter | Type |
|---|---|
index |
number |
Returns
void
focusChooseAllRow()
protectedfocusChooseAllRow():boolean
Defined in: base.ts:2635
Move keyboard focus onto the choose-all row. Returns whether the row is now
focused (false = none is rendered, nothing changed). The item focus is
cleared (focusedIndex becomes -1). Protected so a subclass can wire its
choose-all row's click to focus-then-activate (mirroring how item clicks
call setFocusedIndex before onItemActivated) and use it in
focusInitial (the choose-all row is the listbox's FIRST option).
Returns
boolean
computeTypeaheadClosedStartIndex()
protectedcomputeTypeaheadClosedStartIndex(_list):number
Defined in: base.ts:2984
The option the closed-state typeahead treats as current, as an index into
list, when the typed character is the keystroke that opens the popup.
- The search starts AFTER this option: the opening keystroke is always a
one-character buffer, because
close()and a refusedopen()both empty the buffer. - Default
-1: no current option, so the first match from the top wins. - The focus
focusInitialparks on open is a convenience, not a selection - it must not shift this search. - Single mode overrides this with the chosen item's index, so a typed
initial cycles past the current selection like a native
<select>. - Search internals:
findTypeaheadIndexinkeyboard.ts.
Parameters
| Parameter | Type |
|---|---|
_list |
readonly T[] |
Returns
number
State (protected)
settings
protectedreadonlysettings:S
Defined in: base.ts:972
Resolved settings (defaults applied) - ONE bag for the whole hierarchy.
Typed by the class's S param: a subclass that extends the settings
passes its resolved extra fields through the constructor's
subclassSettings param, and this field is S with no re-typing
(see LLSelectSingle / LLSelectMultiple).
items
protecteditems:T[] =[]
Defined in: base.ts:983
Current item list. Defensive copy of what setItems was given.
focusedIndex
protectedfocusedIndex:number=-1
Defined in: base.ts:992
Position in getVisibleItems() (the rendered list, not items) of the
currently keyboard-focused item, or -1 when nothing is focused (closed
popup, or no items).
changeSource
protectedchangeSource:LLSelectChangeSource='api'
Defined in: base.ts:1002
Who the change being applied right now is attributed to; the variants'
onChange firing reads it. Set to 'user' by withUserChangeSource
and consumed (reset to 'api') by the first onChange fired, so a
nested api-driven change inside an onChange handler reports 'api'.
LLSelectMultiple
Defined in: multiple.ts:187
Multi-selection select. Clicking an item toggles its membership in the
chosen-items set and keeps the popup open. Each item DOM gets
aria-selected="true|false"; the popup list gets
aria-multiselectable="true".
Default trigger display is a count summary ("3 / 10 selected" / "All N
selected" / placeholder when empty). Pass createTriggerContentElFn (or
subclass renderTriggerContent) to customise (e.g. tag chips).
Extends
LLSelectBase<T,GroupKey,S>
Type Parameters
| Type Parameter | Default type | Description |
|---|---|---|
T |
unknown |
item type. |
GroupKey |
string |
group key type of itemToGroupKeyFn; see LLSelectBase. |
S extends LLSelectMultipleSettings<T, GroupKey> |
LLSelectMultipleSettings<T, GroupKey> |
resolved settings type, for subclasses extending the settings bag; see LLSelectBase. |
Selection
getChosenItems()
getChosenItems(): readonly
T[]
Defined in: multiple.ts:237
Return the currently chosen items (insertion order).
Returns
readonly T[]
setChosenItems()
setChosenItems(
items):void
Defined in: multiple.ts:253
Replace the entire chosen-items list.
- The input is copied, and duplicates (per
compareFn) collapse to their first occurrence: the chosen items are a set. - Fires
onChangeonly when the new list differs from the current one. The comparison is order-sensitive: chosen order is visible state (tags render in it). - It ignores disabled state: it can add and drop disabled items, unlike
the
choose*bulk ops. Assigning to a native<select>behaves the same.
Parameters
| Parameter | Type |
|---|---|
items |
readonly T[] |
Returns
void
isChosen()
isChosen(
item):boolean
Defined in: multiple.ts:279
Whether the given item is currently chosen (via compareFn).
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
boolean
toggleItem()
toggleItem(
item):void
Defined in: multiple.ts:309
Toggle the membership of item in the chosen-items set. Adds at the end
if not present; removes if present. Fires onChange.
- While
hideChosenRowsis on, the popup list is rebuilt so the row leaves or re-enters it.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
void
chooseAll()
chooseAll():
void
Defined in: multiple.ts:344
Choose every enabled item.
- It acts on enabled items only, like every
choose*bulk op. Bulk ops mirror clicking, and clicking cannot reach disabled items. - Already-chosen disabled items are preserved. To change disabled items
too, use
setChosenItems. - Fires
onChangeonly when the chosen items actually change.
Returns
void
unchooseAll()
unchooseAll():
void
Defined in: multiple.ts:356
Unchoose every enabled item.
- Already-chosen disabled items are preserved. Bulk ops mirror clicking, and clicking cannot reach disabled items.
- Two paths DO drop them: the clear button, and
setChosenItems([]). - Fires
onChangeonly when the chosen items actually change.
Returns
void
toggleAll()
toggleAll():
void
Defined in: multiple.ts:367
Toggle between "all enabled chosen" and "none chosen".
- It ignores disabled items, like every
choose*bulk op. - This is NOT the in-popup choose-all row's action. The row acts on the visible enabled subset only: see toggleAllVisible.
Returns
void
toggleAllVisible()
toggleAllVisible():
void
Defined in: multiple.ts:394
Toggle the visible enabled items between all-chosen and all-unchosen.
- This is the choose-all row's action (the
chooseAllRowsetting) as a public method. The row delegates here. - Acts on exactly the items that satisfy all of the following:
- Visible: the item is in
getVisibleItems(). It matches the active filter query, and withhideChosenRowsit is not chosen. With no query and withouthideChosenRows, every item is visible. - Enabled: not disabled via
itemDisabledFn, and not in a disabled group.
- Visible: the item is in
- If all of them are already chosen, it unchooses exactly those.
- Otherwise, it chooses the ones still missing.
- Choices outside that set (filtered-out, hidden by
hideChosenRows, or disabled) are preserved either way. - With no filter query and without
hideChosenRows, the acted-on set is every enabled item, the same scope astoggleAll. - Fires
onChangeonly when the chosen items actually change. - The acted-on set is computed by the overridable method
getVisibleEnabledItems, shared with the choose-all row.
Returns
void
getVisibleEnabledItems()
getVisibleEnabledItems(): readonly
T[]
Defined in: multiple.ts:429
Return the items a "select all" acts on: the visible, enabled ones.
- Visible: the item is in
getVisibleItems(). It matches the active filter query, and withhideChosenRowsit is not chosen. With no query and withouthideChosenRows, every item is visible. - Enabled: not disabled via
itemDisabledFn, and not in a disabled group. - The choose-all row (its counts, its tri-state, its click) and
toggleAllVisible()both read this method. - Use it to build your own select-all as an action row, for example in
the trailing rows: count the chosen items with
isChosen, write the text withgetUiTranslationPack().chooseAllRowText(chosen, total), and calltoggleAllVisible()fromonActivate. - Such a row is a command, not the built-in row. It has no
aria-selectedand nodata-chosen-state, the themes give it no tri-state look, it is never the active option when the popup opens, and it stays rendered when this list is empty. For those behaviors, usechooseAllRow. - Override it to change the subset. The tree-select demo narrows it to
leaf nodes; the choose-all row and
toggleAllVisible()follow the override.
Returns
readonly T[]
Items
getItems()
getItems(): readonly
T[]
Defined in: base.ts:1582
Return the current item list, in data order (as passed to setItems).
- The rendered list may differ in order and content: see
getVisibleItems. - Returns the LIVE internal array, typed read-only. Do not mutate it (TS blocks it; plain-JS callers must treat it as frozen).
- Structural mutation would silently bypass chosen-state reconciliation,
re-filtering, and re-render. Replace the list via
setItemsinstead. - Mutating item OBJECTS +
rerender()is the supported in-place path.
Returns
readonly T[]
Inherited from
setItems()
setItems(
items):void
Defined in: base.ts:1670
Replace the item list.
- The input is shallow-copied; later external mutation does not affect the select.
- Items MUST be unique under
compareFn(it defines item identity, and the selection is a set). Duplicates render stale selection DOM; the default compareFn warns once per page, a custom compareFn is the caller's responsibility (not scanned, to keep large lists cheap). - If the popup is open, it re-renders now. While closed, the DOM is
built lazily on the next
open(). - Both shipped variants re-render the trigger content from
onItemsChanged(the multiple count total, custom content that readsitems). LLSelectMultiple'striggerDisplay: 'tags'mode is opt-in;'count'is the default.- When
triggerDisplayis'tags', that content render is one chip per chosen item, unlesscreateTriggerContentElFnreplaces the content. - Subclasses may reconcile chosen-state via onItemsChanged (e.g. single mode drops a chosen value that is no longer in the list).
Parameters
| Parameter | Type |
|---|---|
items |
readonly T[] |
Returns
void
Inherited from
getVisibleItems()
getVisibleItems(): readonly
T[]
Defined in: multiple.ts:459
Return the items the popup list renders, in display order.
base visible items (LLSelectBase.getVisibleItems: gather + filter)
| minus chosen (only while hideChosenRows is on; result cached)
v
visible items (this method's return value)
- Identical to the base behavior, minus the chosen items while
hideChosenRowsis on. - While
hideChosenRowsis on and something is chosen, it returns a cached fresh array, not the live internal one. - The subtraction recomputes only when the base list or the chosen set changed. Calls in between return the same cached array.
Returns
readonly T[]
Overrides
Open & close
open()
open():
void
Defined in: base.ts:1363
Open the popup. Builds item elements lazily, attaches the positioner (which auto-closes if the trigger is scrolled out of view), wires the outside-click handler, and moves keyboard focus into the item list. No-op if already open.
Returns
void
Inherited from
close()
close():
void
Defined in: base.ts:1447
Close the popup. Detaches positioner and outside-click listener, clears the item DOM, and resets focused-item state. No-op if already closed.
Focus return is decided automatically: when DOM focus is still inside
the popup at the moment of close - the filter input (Esc on an empty
filter, a single-select pick, an outside press on a non-focusable area)
or a focusable control the app placed in a header / footer slot (Esc
there, or close() called from its own click) - focus is returned to
the trigger. Tab-away and outside clicks on focusable elements have
already moved focus elsewhere, so we leave it alone.
Returns
void
Inherited from
toggle()
toggle():
void
Defined in: base.ts:1552
Open if closed, close if open.
Returns
void
Inherited from
isOpened()
isOpened():
boolean
Defined in: base.ts:1568
Whether the popup is currently open.
- Pairs with
isDisabled()(state read via method). - The same state is mirrored on the DOM as CSS hooks:
data-state="open|closed"on the trigger,classIdMap.openClasson the root.
Returns
boolean
Inherited from
Trigger
setPlaceholder()
setPlaceholder(
placeholder):void
Defined in: base.ts:1643
Replace the trigger placeholder text at runtime. It is one of the two
settings with a runtime setter (the other is setUiTranslationPack);
both are copy. The rule: LLSelectBaseSettings.
null= fall back to the pack default (uiTranslationPack.triggerPlaceholder), mirroring an unset constructorplaceholder. An explicit value keeps winning over latersetUiTranslationPackcalls, exactly like the constructor input.- Takes effect immediately. Visible only while nothing is chosen - the placeholder never renders otherwise (the trigger is still re-rendered, which also refreshes the hidden accessible-value mirror).
Parameters
| Parameter | Type |
|---|---|
placeholder |
string | null |
Returns
void
Inherited from
Filtering
getFilterQuery()
getFilterQuery():
string
Defined in: base.ts:3271
Return the filter input's current query, exactly the string passed to
filterFn.
- It is
''while the popup is closed, the filter is inactive, or the input is empty. - It resets on close: each open cycle starts empty.
Returns
string
Inherited from
Disabling
setDisabled()
setDisabled(
value):void
Defined in: base.ts:1706
Enable or disable the whole control. Disabled: the trigger gets
aria-disabled + data-disabled (never the native disabled attribute,
which would suppress the hover / focus events a tooltip needs), opening is
blocked, an open popup closes, and the trigger leaves the tab order unless
focusableWhenDisabled is set. Stored as state, mirroring setItems /
setChosenItems (this design keeps mutable state out of settings).
Parameters
| Parameter | Type |
|---|---|
value |
boolean |
Returns
void
Inherited from
isDisabled()
isDisabled():
boolean
Defined in: base.ts:1717
Whether the whole control is disabled.
Returns
boolean
Inherited from
i18n
getUiTranslationPack()
getUiTranslationPack():
Readonly<LLSelectUiTranslationPack>
Defined in: base.ts:1595
Return the resolved UI strings: the built-in English defaults merged
with the uiTranslationPack setting.
- Reuse these in your own UI instead of keeping a second translation
source. For example, a tag remove button tooltip:
sel.getUiTranslationPack().tagRemoveButtonAriaLabel(label). - Returns the LIVE object. Treat it as immutable, like
getItems.
Returns
Readonly<LLSelectUiTranslationPack>
Inherited from
setUiTranslationPack()
setUiTranslationPack(
uiTranslationPack):void
Defined in: base.ts:1616
Replace the UI-translation pack at runtime, so switching language needs
no re-new.
- One of the two settings with a runtime setter (the other is
setPlaceholder); both are copy. The rule: LLSelectBaseSettings. - The pack is resolved exactly like the constructor's: merged over the built-in English pack, NOT over the previously set pack.
- An explicit constructor
placeholderkeeps winning over the new pack'striggerPlaceholder. - Re-renders the trigger and the open popup.
- Also re-applies the pack-owned attributes
rerender()cannot reach: the filter input placeholder and its fallbackaria-label. - The clear button needs no such step:
rerender()rebuilds it, and the rebuild reads the new pack - unless acreateTriggerClearButtonEloverride returns the previous element, which then owns the label.
Parameters
| Parameter | Type |
|---|---|
uiTranslationPack |
Partial<LLSelectUiTranslationPack> |
Returns
void
Inherited from
Lifecycle
rerender()
rerender():
void
Defined in: base.ts:1517
Rebuild the trigger and (while open) the popup list from current state.
- Use it after mutating item OBJECTS in place (e.g.
users[0].name = 'X'). The library cannot detect that on its own. - It re-derives the display order (the
gatherGroupsgather). - While the filter is active, it re-runs the filter against the current item text.
- The refresh is purely visual: it does NOT fire
onChangeand does NOT runonItemsChanged. - Orchestrator: composes
renderTrigger+renderPopupList; touches no DOM directly.
Returns
void
Inherited from
destroy()
destroy():
void
Defined in: base.ts:1537
Tear down the instance: close the popup (which detaches every document /
window listener and the positioner), unwire labelEl (click listener
removed, a minted id removed), remove the library's class and
inline styles from the caller's mount element, and empty it. Idempotent.
The instance must not be used afterwards.
- REQUIRED before discarding an instance that might be OPEN (framework wrappers: call this on unmount) - skipping it there leaks the outside-click / focusout / scroll / resize listeners.
- Discarding a CLOSED instance without
destroy()leaks nothing; it only leaves the root class andoverflow-anchorstyle on the mount.
Returns
void
Inherited from
Constructor
new LLSelectMultiple<
T,GroupKey,S>(targetEl,settings?):LLSelectMultiple<T,GroupKey,S>
Defined in: multiple.ts:207
Build the control inside targetEl.
- Settings are resolved once here; missing fields get defaults.
- They are frozen afterwards, except
placeholderanduiTranslationPack, which have runtime setters; the rule is at LLSelectBaseSettings. - This plain form infers
Tfrom a typed callback insettingswhose signature containsT(itemToStringFn: (u: User) => ...). With no such callback, passTexplicitly:new LLSelectMultiple<string>(...).
Parameters
| Parameter | Type |
|---|---|
targetEl |
HTMLElement |
settings? |
LLSelectMultipleSettingsInput<T, GroupKey> |
Returns
LLSelectMultiple<T, GroupKey, S>
Overrides
Constructor
new LLSelectMultiple<
T,GroupKey,S>(targetEl,settings?,subclassSettings?):LLSelectMultiple<T,GroupKey,S>
Defined in: multiple.ts:213
Subclass form. subclassSettings is the typed pass-through for subclasses
that extend the settings bag further; see LLSelectBase's S param.
Parameters
| Parameter | Type |
|---|---|
targetEl |
HTMLElement |
settings? |
LLSelectSettingsInputOf<S> |
subclassSettings? |
Omit<S, keyof LLSelectMultipleSettings<T, GroupKey>> |
Returns
LLSelectMultiple<T, GroupKey, S>
Overrides
LLSelectBase<T, GroupKey, S>.constructor
DOM elements
rootEl
readonlyrootEl:HTMLElement
Defined in: base.ts:875
The caller-passed mount element, now decorated as the select's root. Library does not replace this node, so the caller's original reference, id, and data-* attributes stay valid.
Inherited from
triggerEl
readonlytriggerEl:HTMLElement
Defined in: base.ts:885
The interactive trigger element. Receives focus, click, and keydown
events; carries aria-expanded, aria-controls, and
data-state="open|closed". Its role depends on the filter mode: combobox
while the filter is inactive (it then also hosts aria-activedescendant) and
button while a filterable popup is open (the filter input hosts
aria-activedescendant). See docs/llm/A11Y.md.
Inherited from
triggerContentEl
readonlytriggerContentEl:HTMLElement
Defined in: base.ts:892
Inner span inside the trigger where text/tags are written.
Subclasses' renderTriggerContent writes here so the sibling arrow slot
is preserved across re-renders.
Inherited from
popupEl
readonlypopupEl:HTMLElement
Defined in: base.ts:909
The outer popup wrapper. Has no ARIA role itself - it just hosts the
popup chrome (future: filter input, toggle-all control) and the inner
popupListEl. Hidden via the hidden attribute when closed; positioned
via inline styles by the positioner when open.
Inherited from
popupListEl
readonlypopupListEl:HTMLElement
Defined in: base.ts:917
The inner element with role="listbox", holding the item children.
Sits inside popupEl so siblings (filter input, toggle-all) can live
above it without violating ARIA's "listbox children must be options"
rule. The trigger's aria-controls points to this element.
Inherited from
popupHeaderEl
readonlypopupHeaderEl:HTMLElement|null
Defined in: base.ts:925
The pinned header container between the filter input and the listbox,
or null when no header content was built. No ARIA role; outside the
scroll area. Built once in the constructor (createPopupHeaderEl) and
kept until destroy(); the library never rebuilds or moves it.
Inherited from
popupFooterEl
readonlypopupFooterEl:HTMLElement|null
Defined in: base.ts:932
The pinned footer container at the bottom of the popup, after the
no-results message, or null when no footer content was built. Same
lifecycle as popupHeaderEl.
Inherited from
popupListPinnedLeadingRowsEl
readonlypopupListPinnedLeadingRowsEl:HTMLElement|null
Defined in: base.ts:950
The wrapper around the pinned leading rows, or null.
- Built once in the constructor when
popupListLeadingRowsPinnedistrue;nullotherwise. - A
divwithrole="presentation"and classpopupListPinnedLeadingRowsClass; the library setsposition: stickyandtop: 0on it inline. - In the listbox only while the leading rows exist. The library moves it
in and out on every list render. Its classes are yours to change after
new. data-edge-to-itemsis set on every list render:"true"when that render lists items,"false"when it lists none; absent before the first render.- It is a CSS hook for the themes: they draw the block's edge line only when it is true, so two blocks that touch draw no line between them.
Inherited from
popupListPinnedTrailingRowsEl
readonlypopupListPinnedTrailingRowsEl:HTMLElement|null
Defined in: base.ts:957
The wrapper around the pinned trailing rows, or null.
- Same contract as popupListPinnedLeadingRowsEl, for
popupListTrailingRowsPinned, withbottom: 0.
Inherited from
classIdMap
readonlyclassIdMap:LLSelectClassIdMap
Defined in: base.ts:962
Resolved class names and ids for this instance.
Inherited from
triggerValueEl
protectedreadonlytriggerValueEl:HTMLElement
Defined in: base.ts:901
Hidden root-level span (sibling of the trigger) mirroring the current
value as plain text. Kept in sync by commitTriggerContentToDom;
referenced by the filterable-mode aria-labelledby chain (see
classIdMap.triggerValueId). Outside the trigger so
triggerEl.textContent stays exactly the visible content.
Inherited from
Subclassing: reactions
onOpened()
protectedonOpened():void
Defined in: base.ts:1753
Subclass hook: called once after the popup finishes opening. Default no-op.
The onOpen setting fires alongside this (both run) - hook for subclass
logic, setting for consumer notification.
Returns
void
Inherited from
onClosed()
protectedonClosed():void
Defined in: base.ts:1758
Subclass hook: called once after the popup finishes closing. Pairs with the onClose setting (both run).
Returns
void
Inherited from
onChosenChanged()
protectedonChosenChanged():void
Defined in: base.ts:1765
Subclass hook: called after the chosen state actually changed, right
before the variant's onChange setting fires (hook first, both run -
same pairing as onOpened / onClosed). Default no-op.
Returns
void
Inherited from
onPopupListActionRowActivated()
protectedonPopupListActionRowActivated(row):void
Defined in: base.ts:2522
Subclass hook: an action row was activated.
- The library calls it on Enter, on Space while the filter is inactive,
and on click, after the disabled re-check, as a user change. You never
call it.
rowcomes from the library: the activated entry. - Default calls the entry's
onActivate. The library changes nothing else: choosing and closing are the entry's job. - Override to react before or after: do your work, then call
super.onPopupListActionRowActivated(row). Without that call the entry'sonActivatenever runs.
Parameters
| Parameter | Type |
|---|---|
row |
LLSelectPopupListActionRow |
Returns
void
Inherited from
withUserChangeSource()
protectedwithUserChangeSource<R>(fn):R
Defined in: base.ts:2582
Run fn with chosen-state changes attributed to the user. The library
wraps exactly its pointer / keyboard entry points with it - option
activation, the tag remove button, the clear button, the choose-all row;
everything else reports 'api'.
Type Parameters
| Type Parameter |
|---|
R |
Parameters
| Parameter | Type |
|---|---|
fn |
() => R |
Returns
R
Inherited from
onItemActivated()
protectedonItemActivated(item):void
Defined in: multiple.ts:633
Toggle on click. Multi mode keeps the popup open.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
void
Overrides
onChooseAllRowActivated()
protectedonChooseAllRowActivated():void
Defined in: multiple.ts:711
Activate the choose-all row: delegates to toggleAllVisible.
Returns
void
Overrides
onItemsChanged()
protectedonItemsChanged():void
Defined in: multiple.ts:745
Re-match the chosen entries against the new list after setItems.
- Entries the list no longer holds (by
compareFn) are dropped andonChangefires for the drop. - When the list holds a compareFn-equal but DIFFERENT object (
track bystyle reload: same key, fresh fields), the stored reference is swapped to the list's object. A reference swap is not a logical change, so it does not fireonChange. - The trigger content re-renders after every
setItems, swap or not. - Why: the count summary shows the list total, and a custom
createTriggerContentElFnreceivesitems. - The arrow re-renders only when a chosen entry is dropped, because that runs the whole trigger.
triggerDisplay: 'tags'is opt-in;'count'is the default.- When
triggerDisplayis'tags', that render is one chip per chosen item persetItems, unlesscreateTriggerContentElFnreplaces the content. - That cost is acceptable:
setItemsis a bulk call.
Returns
void
Overrides
Subclassing: rendering
renderTrigger()
protectedrenderTrigger():void
Defined in: base.ts:1810
Orchestrator: composes the clear-button rebuild + renderTriggerContent +
renderTriggerArrow to (re)build the whole trigger from state; touches no
DOM directly. Subclasses normally override renderTriggerContent,
not this.
- Runs on every change of the chosen value, the placeholder or the pack.
rerender()runs it too.- While
clearableis on, the first run builds the clear button and every later run swaps it for whatevercreateTriggerClearButtonElreturns: a fresh button from the base implementation, like the arrow. An override may return the previous element; it is then kept in place. - If the button is rebuilt and the old one held focus - on it or inside its icon - the rebuilt BUTTON gets it.
- If the builder returned the same element, nothing was rebuilt, and focus goes back to the node that held it, if that node is still inside the button and can take focus; otherwise focus stays on the button.
setItemsrunsrenderTriggerContentalone, because only the content reads the list (the multiple count total, a customcreateTriggerContentElFn'sitems).- A
setItemsthat drops the chosen entry runs the whole trigger. - Runs once from the
LLSelectSingle/LLSelectMultipleconstructor, right aftersuper(). - On that first run a FURTHER subclass's own fields are still
undefined: JS runs a subclass's field initializers only after its super constructor returns (virtual-call-in-constructor). An override of a trigger method (renderTriggerContent, or acreate*Elit calls) that reads such a field seesundefinedthere. - The recipe: put construction-time configuration in the typed
subclassSettingsconstructor param.this.settingsis complete before any construction code runs. - For genuine instance state, tolerate defaults during construction, or call
rerender()at the end of your own constructor. - The popup-list methods do NOT run here; they wait for
open(). See DESIGN.md "Customization model".
Returns
void
Inherited from
commitTriggerContentToDom()
protectedcommitTriggerContentToDom(content,plainTextValue?):void
Defined in: base.ts:1833
Write the trigger's content slot (triggerContentEl), replacing whatever
was there; the sibling arrow slot is untouched. The single DOM-writing
primitive behind every renderTriggerContent path.
string-> set astextContent(plain text, NOT parsed as HTML). Used for the default placeholder /itemToStringtext / count summary.HTMLElement-> inserted as-is viareplaceChildren; caller owns the node. Used for whatever thecreateTriggerContentElFnsetting returned.- Also mirrors the value into the hidden
triggerValueEl(the accessible name source): the string itself, elseplainTextValue, else the element'stextContent. PassplainTextValuewhenever the element contains labelled controls (tag remove buttons) or icon-only content - the mirror is what AT announces as the field's value. Called byrenderTriggerContent- the base default and theLLSelectSingle/LLSelectMultipleoverrides.
Parameters
| Parameter | Type |
|---|---|
content |
string | HTMLElement |
plainTextValue? |
string |
Returns
void
Inherited from
syncEmptyStateToDom()
protectedsyncEmptyStateToDom():void
Defined in: base.ts:1850
Mirror the empty/filled state onto the trigger's data-empty attribute
("true" when isEmpty(), else "false"). A CSS / AT styling hook,
independent of the rendered content. Called by the subclass
renderTriggerContent overrides.
Returns
void
Inherited from
createTriggerArrowContentEl()
protectedcreateTriggerArrowContentEl(state):HTMLElement|SVGElement|null
Defined in: base.ts:1896
Trigger arrow element for the given open state.
- Default reads
createTriggerArrowContentElFn;null(setting unset, or returned for a state) = no arrow for that state. - Override only when extending; for one-off arrows pass the setting.
Mirrors
createTriggerClearButtonEl/createItemContentEl.
Parameters
| Parameter | Type |
|---|---|
state |
{ isOpened: boolean; } |
state.isOpened |
boolean |
Returns
HTMLElement | SVGElement | null
Inherited from
renderPopupList()
protectedrenderPopupList():void
Defined in: base.ts:1929
Orchestrator: composes createItemEl (build) + computePopupSegments +
commitPopupSegmentsToDom (write) to rebuild the popup list from
getVisibleItems(); touches no DOM directly. Called by open() and by
setItems() while open. Also clamps focusedIndex if the list shrank and
re-applies focus visuals.
- Extend it by wrapping: override, do your work before or after, then
call
super.renderPopupList(). The ui-select bridge frees its row scopes this way. Or override one of the methods it calls throughthis:createItemEl,createPopupListChooseAllRowEl,createPopupListLeadingActionRowEl/createPopupListTrailingActionRowEl,itemToGroupKey,getVisibleItems. - Its other internals stay private on purpose. They re-establish the
itemEls[i] <-> getVisibleItems()[i]alignment as one unit, so no subclass can leave keyboard nav oraria-activedescendanthalf-synced.
Returns
void
Inherited from
createGroupEl()
protectedcreateGroupEl(key,index,items,itemEls):HTMLElement
Defined in: base.ts:2064
Build the whole DOM element for one group container.
- The library calls it, once per group of the current render, on every list render. You never call it yourself.
- All four params come from the library. Forward them to
superunchanged. indexis the group's position among this render's groups, counted from 0. It only mints the group id. It is not an identity: it changes whenever the visible list changes.- To change only the label's content, do not override this. Pass the
createGroupLabelContentElFnsetting instead. - To change the element itself, override it, call
super.createGroupEl(...), and edit the returned element. Keep theroleandaria-labelthe base set. - Internals: the base sets the id,
role="group"named bygroupKeyToString(aria-label), anaria-hiddenvisible label element filled from createGroupLabelContentEl (else the plain label text), then the group's item elements;aria-disabled+data-disabledwhen the group is disabled.
Parameters
| Parameter | Type | Description |
|---|---|---|
key |
GroupKey |
the group's key, supplied by the library |
index |
number |
the group's position among this render's groups, supplied by the library |
items |
readonly T[] |
the group's items, supplied by the library (for counts / rich content) |
itemEls |
HTMLElement[] |
the group's already-built option elements, supplied by the library |
Returns
HTMLElement
Inherited from
createGroupLabelContentEl()
protectedcreateGroupLabelContentEl(key,itemsInGroup):HTMLElement|null
Defined in: base.ts:2098
Group label -> its visible content element (icon / count badge / rich
markup). Mirrors createItemContentEl.
- Default reads
createGroupLabelContentElFn, elsenullsocreateGroupEluses plain text fromgroupKeyToString. - The group's accessible name stays
groupKeyToString(containeraria-label); this fills only the visible,aria-hiddenlabel content. - Override only when extending; for one-off rich labels pass the setting.
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
itemsInGroup |
readonly T[] |
Returns
HTMLElement | null
Inherited from
replacePopupListItemElInDom()
protectedreplacePopupListItemElInDom(item):void
Defined in: base.ts:2112
Re-render a single item's element in place instead of rebuilding the whole popup list. The DOM work is O(1) regardless of list size, so flipping one selection in a 10k-item list does not recreate 10k nodes (the lookup to find the item is O(n), but that is a cheap comparison loop next to DOM mutation). No-op if the popup is closed or the item is not in the current list. Used by multi-select toggle.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
void
Inherited from
createItemContentEl()
protectedcreateItemContentEl(item):HTMLElement|null
Defined in: base.ts:2222
Item -> the visible content of its list row (icon + text etc.).
- Default reads
createItemContentElFn, elsenullsocreateItemEluses the plain-text default fromitemToString. - Override only when extending; for one-off rich content pass the setting.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
HTMLElement | null
Inherited from
createPopupListLeadingActionRowEl()
protectedcreatePopupListLeadingActionRowEl(row,index):HTMLElement
Defined in: base.ts:2427
Build the whole DOM element for one leading action row (above the items).
- The library calls it, once per entry of
popupListLeadingActionRows, on every list render and after every chosen change. You never call it. - Both params come from the library. Forward them to
superunchanged.rowis the entry;indexis its position in that array, counted from 0, used to mint the id. It is not an identity. - To change only what the row shows, do not override this: give the entry
a
createContentElFn. - To change the element itself, override it, call
super.createPopupListLeadingActionRowEl(row, index), and edit the returned element. Keep theidandrole; put no focusable control inside. - Internals: a
divwithrole="option", the id<listbox id>-action-row-leading<index>,itemClasspluspopupListActionRowClass, the visible content from createPopupListActionRowContentEl (elsetextContentfromtextFn),aria-label=textFn()when the content is custom, and eitheraria-disabledplus the disabled class (isPopupListActionRowDisabled) or a click handler that focuses the row, then runs onPopupListActionRowActivated. Noaria-selected: a command has no selected state.
Parameters
| Parameter | Type | Description |
|---|---|---|
row |
LLSelectPopupListActionRow |
the entry, supplied by the library |
index |
number |
the entry's position in popupListLeadingActionRows, supplied by the library |
Returns
HTMLElement
Inherited from
createPopupListTrailingActionRowEl()
protectedcreatePopupListTrailingActionRowEl(row,index):HTMLElement
Defined in: base.ts:2450
Build the whole DOM element for one trailing action row (below the items).
- The library calls it, once per entry of
popupListTrailingActionRows, on every list render and after every chosen change. You never call it. - Both params come from the library. Forward them to
superunchanged.rowis the entry;indexis its position in that array, counted from 0, used to mint the id. It is not an identity. - To change only what the row shows, do not override this: give the entry
a
createContentElFn. - To change the element itself, override it, call
super.createPopupListTrailingActionRowEl(row, index), and edit the returned element. Keep theidandrole; put no focusable control inside. - Internals: identical to createPopupListLeadingActionRowEl
except the id,
<listbox id>-action-row-trailing<index>.
Parameters
| Parameter | Type | Description |
|---|---|---|
row |
LLSelectPopupListActionRow |
the entry, supplied by the library |
index |
number |
the entry's position in popupListTrailingActionRows, supplied by the library |
Returns
HTMLElement
Inherited from
createPopupListActionRowContentEl()
protectedcreatePopupListActionRowContentEl(row):HTMLElement|null
Defined in: base.ts:2493
An action row's visible content element.
- The library calls it from the row builders, once per row render. You
never call it.
rowcomes from the library. - Default reads the entry's
createContentElFn;null(unset, or returned) = plain text fromtextFn. - Override only when extending; for one-off content give the entry a
createContentElFn.
Parameters
| Parameter | Type |
|---|---|
row |
LLSelectPopupListActionRow |
Returns
HTMLElement | null
Inherited from
replacePopupListActionRowElsInDom()
protectedreplacePopupListActionRowElsInDom():void
Defined in: base.ts:2538
Rebuild every rendered action row in place, so textFn / disabledFn
reflect the current state; the row holding the active option keeps it.
- The library calls it after every chosen change, right after
onChangefired (a row's text may read what the handler wrote). Subclasses may call it after a state change of their own. - No-op while closed, or when both row arrays are empty - instances without rows pay nothing.
- O(rows) DOM work; the item rows are untouched.
Returns
void
Inherited from
replaceChooseAllRowElInDom()
protectedreplaceChooseAllRowElInDom():void
Defined in: base.ts:2652
Rebuild the choose-all row in place (tri-state / text refresh) without
touching the item elements - O(1) DOM work, mirroring
replacePopupListItemElInDom. Falls back to a full renderPopupList
when the row becomes inapplicable (builder returns null). No-op while
closed or when no choose-all row is rendered.
Returns
void
Inherited from
createTriggerClearButtonEl()
protectedcreateTriggerClearButtonEl():HTMLElement
Defined in: base.ts:3047
Build the clear (x) button for the clearable trigger slot.
- The library owns the button, its click (stops propagation so it never
toggles the popup, then
clearSelection; a no-op while the control is disabled) and itsaria-label(text fromuiTranslationPack.triggerClearButtonAriaLabel). createTriggerClearButtonContentElFnoptionally fills the icon; else the theme's CSS glyph draws it.- The theme hides the button via
data-emptywhile nothing is chosen. - It runs on every trigger render (
renderTrigger). - The first run builds the button.
- For
LLSelectSingle/LLSelectMultipleand their subclasses, that first run is the variant constructor's render, right aftersuper(), so it happens before a FURTHER subclass's field initializers. - A direct
LLSelectBasesubclass gets the button on its first trigger render (its ownrenderTrigger()call, orrerender()/setPlaceholder); until then the trigger is unrendered and there is no button. - Every later run (a value change,
setPlaceholder,setUiTranslationPack,rerender()) swaps the button in place, unless this method returns the previous element - then it stays in place. - The base implementation returns a fresh element each run, so, like the arrow, nothing put on it from outside survives a render; customize it here.
- An override that returns the same element every time owns everything
the rebuild would otherwise refresh on it, including its
aria-labelaftersetUiTranslationPack. - An override that reads subclass fields calls
rerender()at the end of its constructor, like every other trigger method.
Returns
HTMLElement
Inherited from
createTriggerClearButtonContentEl()
protectedcreateTriggerClearButtonContentEl():HTMLElement|SVGElement|null
Defined in: base.ts:3174
Clear button's visible content (its x icon).
- Default reads
createTriggerClearButtonContentElFn;null(setting unset, or returned) = no icon - the theme's CSS glyph draws the x. - Override only when extending; for one-off icons pass the setting.
Returns
HTMLElement | SVGElement | null
Inherited from
createPopupListNoResultsContentEl()
protectedcreatePopupListNoResultsContentEl(query):HTMLElement|null
Defined in: base.ts:3356
The no-results message's visible content (rich empty-state).
- Default reads
createPopupListNoResultsContentElFn;null(setting unset, or returned) = plain text fromuiTranslationPack.popupListNoResults. - Override only when extending; for one-off content pass the setting.
Parameters
| Parameter | Type |
|---|---|
query |
string |
Returns
HTMLElement | null
Inherited from
createPopupHeaderEl()
protectedcreatePopupHeaderEl():HTMLElement|null
Defined in: base.ts:3376
Build the pinned header container between the filter input and the listbox.
- The library calls it once, inside the constructor. You never call it.
- It takes no params. The default asks createPopupHeaderContentEl
for content;
nullcontent = no container, andpopupHeaderElstaysnull. - To supply content without subclassing, pass
createPopupHeaderContentElFn. - To change the container itself, override it: call
super.createPopupHeaderEl()and edit the returned element, or return your owndiv. Returning non-null builds the slot even without the setting. Keep it role-free: it is not part of the listbox. - Internals: the base builds a
divwithclassIdMap.popupHeaderClassand inlineflex: none(the popup is a flex column and only the listbox may flex), then appends the content.
Returns
HTMLElement | null
Inherited from
createPopupHeaderContentEl()
protectedcreatePopupHeaderContentEl():HTMLElement|null
Defined in: base.ts:3390
The pinned header's content element.
- The library calls it once, from createPopupHeaderEl, inside the constructor. You never call it.
- Default calls
createPopupHeaderContentElFnwith a LLSelectConstructionContext;null(setting unset, or returned) = no header at all. - Override only when extending; for one-off content pass the setting.
Returns
HTMLElement | null
Inherited from
createPopupFooterEl()
protectedcreatePopupFooterEl():HTMLElement|null
Defined in: base.ts:3410
Build the pinned footer container at the bottom of the popup.
- The library calls it once, inside the constructor. You never call it.
- It takes no params. The default asks createPopupFooterContentEl
for content;
nullcontent = no container, andpopupFooterElstaysnull. - To supply content without subclassing, pass
createPopupFooterContentElFn. - To change the container itself, override it: call
super.createPopupFooterEl()and edit the returned element, or return your owndiv. Returning non-null builds the slot even without the setting. Keep it role-free: it is not part of the listbox. - Internals: the base builds a
divwithclassIdMap.popupFooterClassand inlineflex: none(only the listbox may flex), then appends the content.
Returns
HTMLElement | null
Inherited from
createPopupFooterContentEl()
protectedcreatePopupFooterContentEl():HTMLElement|null
Defined in: base.ts:3424
The pinned footer's content element.
- The library calls it once, from createPopupFooterEl, inside the constructor. You never call it.
- Default calls
createPopupFooterContentElFnwith a LLSelectConstructionContext;null(setting unset, or returned) = no footer at all. - Override only when extending; for one-off content pass the setting.
Returns
HTMLElement | null
Inherited from
renderTriggerContent()
protectedrenderTriggerContent():void
Defined in: multiple.ts:487
Orchestrator: composes syncEmptyStateToDom + commitTriggerContentToDom
to (re)build the trigger from state; touches no DOM directly. Default text
is a count summary; override (or pass the createTriggerContentElFn
setting) to display tags / custom markup / etc.
- If 0 items are chosen, the text is
placeholder. - If n > 0, the text is
uiTranslationPack.triggerCountSummary(n, total)(English default:"n / total selected", or"All n selected"when all are chosen).
Returns
void
Overrides
createTagsEl()
protectedcreateTagsEl():HTMLElement
Defined in: multiple.ts:514
Build the tag-list element for 'tags' mode: one chip per chosen item.
Override for full control of the chip strip (the trigger-level equivalent
of overriding createItemEl).
Returns
HTMLElement
createTagEl()
protectedcreateTagEl(item):HTMLElement
Defined in: multiple.ts:532
Build one removable tag chip: its content (from createTagContentEl, else
plain itemToString) plus its remove (x) button (from createTagRemoveButtonEl).
A chip whose item is effectively disabled gets aria-disabled="true" +
tagDisabledClass, and its x turns inert - mirroring a disabled option row.
Override for full control of the chip container; override the two sub-parts
for content-only / remove-button-only changes.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
HTMLElement
createTagRemoveButtonEl()
protectedcreateTagRemoveButtonEl(item):HTMLElement
Defined in: multiple.ts:564
Build one chip's remove (x) button. The library owns the button + its click
(stopPropagation so it never toggles the popup, then toggleItem; a no-op
while the whole control OR the item itself is disabled) + tabindex="-1" +
aria-label (from itemToTagRemoveButtonAriaLabel). An effectively-disabled
item's button also gets aria-disabled="true".
createTagRemoveButtonContentElFn optionally fills the icon, else the theme's CSS glyph.
Mirrors the clear button's createTriggerClearButtonEl. Override for full control of
the button element.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
HTMLElement
createTagRemoveButtonContentEl()
protectedcreateTagRemoveButtonContentEl(item):HTMLElement|SVGElement|null
Defined in: multiple.ts:594
One chip's remove-button visible content (its x icon). Mirrors
createTriggerClearButtonContentEl.
- Default reads
createTagRemoveButtonContentElFn;null(setting unset, or returned) = no icon - the theme's CSS glyph draws the x. - Override only when extending; for one-off icons pass the setting.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
HTMLElement | SVGElement | null
createTagContentEl()
protectedcreateTagContentEl(item):HTMLElement|null
Defined in: multiple.ts:605
Per-chip visible content in 'tags' mode. Mirrors createItemContentEl.
Default reads createTagContentElFn, else null so createTagEl falls
back to plain text from itemToString.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
HTMLElement | null
createPopupListChooseAllRowEl()
protectedcreatePopupListChooseAllRowEl():HTMLElement|null
Defined in: multiple.ts:654
Build the choose-all row (chooseAllRow setting) as the listbox's
leading role="option" row: data-chosen-state="none|some|all" (a CSS
styling hook), aria-selected only when ALL visible
enabled items are chosen, accessible name + visible text from
uiTranslationPack.chooseAllRowText(chosenCount, totalCount) over the visible
enabled subset. null when the setting is off or nothing is actionable.
Returns
HTMLElement | null
Overrides
createChooseAllRowContentEl()
protectedcreateChooseAllRowContentEl(chosenState,chosenCount,totalCount):HTMLElement|null
Defined in: multiple.ts:698
The choose-all row's visible content (rich tri-state). Mirrors
createItemContentEl.
- Default reads
createChooseAllRowContentElFn;null(setting unset, or returned) = the default content: plain text fromuiTranslationPack.chooseAllRowText. - Override only when extending; for one-off content pass the setting.
Parameters
| Parameter | Type |
|---|---|
chosenState |
LLSelectChosenState |
chosenCount |
number |
totalCount |
number |
Returns
HTMLElement | null
createItemEl()
protectedcreateItemEl(item,index):HTMLElement
Defined in: multiple.ts:719
Mark each item with aria-selected reflecting its chosen state.
Parameters
| Parameter | Type |
|---|---|
item |
T |
index |
number |
Returns
HTMLElement
Overrides
Subclassing: semantics
itemToString()
protecteditemToString(item):string
Defined in: base.ts:2210
Map an item to its display string. The library calls this everywhere it needs an item's text: list rows, the single trigger text, default filter.
- Default reads the
itemToStringFnsetting, elseString(item). - Configure via
itemToStringFn(no subclass needed). - Override only when extending (a new select type); your override replaces
the default. For HTML content, subclass
createItemEl.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
string
Inherited from
isItemEffectivelyDisabled()
protectedisItemEffectivelyDisabled(item):boolean
Defined in: base.ts:2236
Whether item is effectively disabled - by itemDisabledFn, or because
its group is disabled (groupDisabledFn). Group-disabled layers on top,
so every item-disabled behavior (no selection, keyboard skip, aria)
covers grouped items with no extra code. False when neither applies.
The whole-control disabled state (isDisabled()) is a separate layer,
not part of this answer.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
boolean
Inherited from
itemToGroupKey()
protecteditemToGroupKey(item):GroupKey|null
Defined in: base.ts:2255
Map an item to its group key, or null when it belongs to no group.
The authoritative method: rendering, the gatherGroups gather, and the
disabled layer all resolve keys through this method, so an override
drives them all - returning keys turns grouping on even with the setting
unset (all-null keys = flat list). An override reading external state
must call rerender() after that state changes (same contract as
mutating item objects).
- Default reads
itemToGroupKeyFn, elsenull(grouping off). - Override only when extending; configure via the setting.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
GroupKey | null
Inherited from
groupKeyToString()
protectedgroupKeyToString(key):string
Defined in: base.ts:2265
Map a group key to its label display text.
- Default reads
groupKeyToStringFn, elseString(key).
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
Returns
string
Inherited from
isGroupDisabled()
protectedisGroupDisabled(key):boolean
Defined in: base.ts:2274
Whether the whole group key is disabled per groupDisabledFn (false when unset).
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
Returns
boolean
Inherited from
isPopupListActionRowDisabled()
protectedisPopupListActionRowDisabled(row):boolean
Defined in: base.ts:2505
Whether an action row is disabled right now.
- The library calls it from the row builders (once per row render) and
again at activation. You never call it.
rowcomes from the library. - Default reads the entry's
disabledFn;null/ omitted = never disabled.
Parameters
| Parameter | Type |
|---|---|
row |
LLSelectPopupListActionRow |
Returns
boolean
Inherited from
matchesQuery()
protectedmatchesQuery(item,query):boolean
Defined in: base.ts:3283
Per-item match predicate for the filter input.
- Default reads
filterFn; else case-insensitive substring onitemToString. - Override only when extending (subclass-wide custom matching); for a one-off match rule pass the setting.
Parameters
| Parameter | Type |
|---|---|
item |
T |
query |
string |
Returns
boolean
Inherited from
itemToTagRemoveButtonAriaLabel()
protecteditemToTagRemoveButtonAriaLabel(item):string
Defined in: multiple.ts:617
Item -> its remove button's accessible name in 'tags' mode.
- Default:
uiTranslationPack.tagRemoveButtonAriaLabel(itemToString(item)). - Override only when extending (e.g. a name from another item field);
per-locale text goes through the
uiTranslationPacksetting.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
string
isEmpty()
protectedisEmpty():boolean
Defined in: multiple.ts:625
No selection iff the chosen set is empty. Drives the trigger's data-empty.
Returns
boolean
Overrides
clearSelection()
protectedclearSelection():void
Defined in: multiple.ts:641
Clear button empties the chosen-items set to [].
Returns
void
Overrides
Subclassing: focus
findNextEnabledIndex()
protectedfindNextEnabledIndex(start,step,list):number
Defined in: base.ts:2285
First enabled index scanning from start (inclusive) by step (+1 / -1).
Returns -1 if no enabled item lies in that direction. Used to skip disabled
items during keyboard nav and initial focus.
Parameters
| Parameter | Type |
|---|---|
start |
number |
step |
number |
list |
readonly T[] |
Returns
number
Inherited from
setFocusedIndex()
protectedsetFocusedIndex(index):void
Defined in: base.ts:2617
Move keyboard focus to the item at index. The value is clamped to
[-1, items.length-1]; pass -1 to clear focus. Updates the focused
class, aria-activedescendant, and scrolls the item into view. No-op
if the clamped value equals the current focused index.
Parameters
| Parameter | Type |
|---|---|
index |
number |
Returns
void
Inherited from
focusChooseAllRow()
protectedfocusChooseAllRow():boolean
Defined in: base.ts:2635
Move keyboard focus onto the choose-all row. Returns whether the row is now
focused (false = none is rendered, nothing changed). The item focus is
cleared (focusedIndex becomes -1). Protected so a subclass can wire its
choose-all row's click to focus-then-activate (mirroring how item clicks
call setFocusedIndex before onItemActivated) and use it in
focusInitial (the choose-all row is the listbox's FIRST option).
Returns
boolean
Inherited from
computeTypeaheadClosedStartIndex()
protectedcomputeTypeaheadClosedStartIndex(_list):number
Defined in: base.ts:2984
The option the closed-state typeahead treats as current, as an index into
list, when the typed character is the keystroke that opens the popup.
- The search starts AFTER this option: the opening keystroke is always a
one-character buffer, because
close()and a refusedopen()both empty the buffer. - Default
-1: no current option, so the first match from the top wins. - The focus
focusInitialparks on open is a convenience, not a selection - it must not shift this search. - Single mode overrides this with the chosen item's index, so a typed
initial cycles past the current selection like a native
<select>. - Search internals:
findTypeaheadIndexinkeyboard.ts.
Parameters
| Parameter | Type |
|---|---|
_list |
readonly T[] |
Returns
number
Inherited from
focusInitial()
protectedfocusInitial():void
Defined in: multiple.ts:780
On open, focus the first chosen item (if present and enabled). Otherwise
the FIRST OPTION - which is the choose-all row when rendered (A11Y.md:
activedescendant points at the first chosen option, else the first
option; the row is the topmost option), so keyboard users discover it
immediately. Else the first enabled item. Indices are into
getVisibleItems().
Returns
void
Overrides
State (protected)
settings
protectedreadonlysettings:S
Defined in: base.ts:972
Resolved settings (defaults applied) - ONE bag for the whole hierarchy.
Typed by the class's S param: a subclass that extends the settings
passes its resolved extra fields through the constructor's
subclassSettings param, and this field is S with no re-typing
(see LLSelectSingle / LLSelectMultiple).
Inherited from
items
protecteditems:T[] =[]
Defined in: base.ts:983
Current item list. Defensive copy of what setItems was given.
Inherited from
focusedIndex
protectedfocusedIndex:number=-1
Defined in: base.ts:992
Position in getVisibleItems() (the rendered list, not items) of the
currently keyboard-focused item, or -1 when nothing is focused (closed
popup, or no items).
Inherited from
changeSource
protectedchangeSource:LLSelectChangeSource='api'
Defined in: base.ts:1002
Who the change being applied right now is attributed to; the variants'
onChange firing reads it. Set to 'user' by withUserChangeSource
and consumed (reset to 'api') by the first onChange fired, so a
nested api-driven change inside an onChange handler reports 'api'.
Inherited from
chosenItems
protectedchosenItems: readonlyT[] =[]
Defined in: multiple.ts:195
Currently chosen items, in insertion order.
LLSelectSingle
Defined in: single.ts:75
Single-selection select. Picking an item replaces any prior chosen item
and closes the popup. Use setChosenItem(undefined) to clear the selection.
Extends
LLSelectBase<T,GroupKey,S>
Type Parameters
| Type Parameter | Default type | Description |
|---|---|---|
T |
unknown |
item type. Supply your own compareFn for non-primitive T. |
GroupKey |
string |
group key type of itemToGroupKeyFn; see LLSelectBase. |
S extends LLSelectSingleSettings<T, GroupKey> |
LLSelectSingleSettings<T, GroupKey> |
resolved settings type, for subclasses extending the settings bag; see LLSelectBase. |
Selection
getChosenItem()
getChosenItem():
T|undefined
Defined in: single.ts:115
Return the currently chosen item, or undefined if none.
Returns
T | undefined
setChosenItem()
setChosenItem(
item):void
Defined in: single.ts:131
Set the chosen item programmatically.
undefinedclears the choice.- Fires
onChangeonly when the item actually differs from the current one (compared viacompareFn). - Accepts an item that is not (yet) in the items list, for async data
flows. If a later
setItemsdoes not include it, it is dropped automatically. - It does not check disabled state: a disabled item can be chosen
programmatically. Native
<select>behaves the same.
Parameters
| Parameter | Type |
|---|---|
item |
T | undefined |
Returns
void
Items
getItems()
getItems(): readonly
T[]
Defined in: base.ts:1582
Return the current item list, in data order (as passed to setItems).
- The rendered list may differ in order and content: see
getVisibleItems. - Returns the LIVE internal array, typed read-only. Do not mutate it (TS blocks it; plain-JS callers must treat it as frozen).
- Structural mutation would silently bypass chosen-state reconciliation,
re-filtering, and re-render. Replace the list via
setItemsinstead. - Mutating item OBJECTS +
rerender()is the supported in-place path.
Returns
readonly T[]
Inherited from
setItems()
setItems(
items):void
Defined in: base.ts:1670
Replace the item list.
- The input is shallow-copied; later external mutation does not affect the select.
- Items MUST be unique under
compareFn(it defines item identity, and the selection is a set). Duplicates render stale selection DOM; the default compareFn warns once per page, a custom compareFn is the caller's responsibility (not scanned, to keep large lists cheap). - If the popup is open, it re-renders now. While closed, the DOM is
built lazily on the next
open(). - Both shipped variants re-render the trigger content from
onItemsChanged(the multiple count total, custom content that readsitems). LLSelectMultiple'striggerDisplay: 'tags'mode is opt-in;'count'is the default.- When
triggerDisplayis'tags', that content render is one chip per chosen item, unlesscreateTriggerContentElFnreplaces the content. - Subclasses may reconcile chosen-state via onItemsChanged (e.g. single mode drops a chosen value that is no longer in the list).
Parameters
| Parameter | Type |
|---|---|
items |
readonly T[] |
Returns
void
Inherited from
getVisibleItems()
getVisibleItems(): readonly
T[]
Defined in: base.ts:3241
Return the items the popup list renders, in display order.
items (setItems)
| gather (only with grouping on; result cached until setItems)
v
display base list
| filter query (only while a query is active)
v
visible items (this method's return value)
| render
v
DOM rows
- If no filter query is active (including while closed), it returns the
full list, gathered per
gatherGroupswhen grouping is on. - If a filter query is active, it returns the matching subset.
- Disabled items are included. They render (grayed); only actions skip them (keyboard focus, the choose-all row's subset).
- Returns the LIVE internal array, typed read-only. Never mutate it
(see
getItems). - Subclasses use it too (e.g. for selection-by-index), and may override
it to add a step:
LLSelectMultipledoes forhideChosenRows.
Returns
readonly T[]
Inherited from
Open & close
open()
open():
void
Defined in: base.ts:1363
Open the popup. Builds item elements lazily, attaches the positioner (which auto-closes if the trigger is scrolled out of view), wires the outside-click handler, and moves keyboard focus into the item list. No-op if already open.
Returns
void
Inherited from
close()
close():
void
Defined in: base.ts:1447
Close the popup. Detaches positioner and outside-click listener, clears the item DOM, and resets focused-item state. No-op if already closed.
Focus return is decided automatically: when DOM focus is still inside
the popup at the moment of close - the filter input (Esc on an empty
filter, a single-select pick, an outside press on a non-focusable area)
or a focusable control the app placed in a header / footer slot (Esc
there, or close() called from its own click) - focus is returned to
the trigger. Tab-away and outside clicks on focusable elements have
already moved focus elsewhere, so we leave it alone.
Returns
void
Inherited from
toggle()
toggle():
void
Defined in: base.ts:1552
Open if closed, close if open.
Returns
void
Inherited from
isOpened()
isOpened():
boolean
Defined in: base.ts:1568
Whether the popup is currently open.
- Pairs with
isDisabled()(state read via method). - The same state is mirrored on the DOM as CSS hooks:
data-state="open|closed"on the trigger,classIdMap.openClasson the root.
Returns
boolean
Inherited from
Trigger
setPlaceholder()
setPlaceholder(
placeholder):void
Defined in: base.ts:1643
Replace the trigger placeholder text at runtime. It is one of the two
settings with a runtime setter (the other is setUiTranslationPack);
both are copy. The rule: LLSelectBaseSettings.
null= fall back to the pack default (uiTranslationPack.triggerPlaceholder), mirroring an unset constructorplaceholder. An explicit value keeps winning over latersetUiTranslationPackcalls, exactly like the constructor input.- Takes effect immediately. Visible only while nothing is chosen - the placeholder never renders otherwise (the trigger is still re-rendered, which also refreshes the hidden accessible-value mirror).
Parameters
| Parameter | Type |
|---|---|
placeholder |
string | null |
Returns
void
Inherited from
Filtering
getFilterQuery()
getFilterQuery():
string
Defined in: base.ts:3271
Return the filter input's current query, exactly the string passed to
filterFn.
- It is
''while the popup is closed, the filter is inactive, or the input is empty. - It resets on close: each open cycle starts empty.
Returns
string
Inherited from
Disabling
setDisabled()
setDisabled(
value):void
Defined in: base.ts:1706
Enable or disable the whole control. Disabled: the trigger gets
aria-disabled + data-disabled (never the native disabled attribute,
which would suppress the hover / focus events a tooltip needs), opening is
blocked, an open popup closes, and the trigger leaves the tab order unless
focusableWhenDisabled is set. Stored as state, mirroring setItems /
setChosenItems (this design keeps mutable state out of settings).
Parameters
| Parameter | Type |
|---|---|
value |
boolean |
Returns
void
Inherited from
isDisabled()
isDisabled():
boolean
Defined in: base.ts:1717
Whether the whole control is disabled.
Returns
boolean
Inherited from
i18n
getUiTranslationPack()
getUiTranslationPack():
Readonly<LLSelectUiTranslationPack>
Defined in: base.ts:1595
Return the resolved UI strings: the built-in English defaults merged
with the uiTranslationPack setting.
- Reuse these in your own UI instead of keeping a second translation
source. For example, a tag remove button tooltip:
sel.getUiTranslationPack().tagRemoveButtonAriaLabel(label). - Returns the LIVE object. Treat it as immutable, like
getItems.
Returns
Readonly<LLSelectUiTranslationPack>
Inherited from
setUiTranslationPack()
setUiTranslationPack(
uiTranslationPack):void
Defined in: base.ts:1616
Replace the UI-translation pack at runtime, so switching language needs
no re-new.
- One of the two settings with a runtime setter (the other is
setPlaceholder); both are copy. The rule: LLSelectBaseSettings. - The pack is resolved exactly like the constructor's: merged over the built-in English pack, NOT over the previously set pack.
- An explicit constructor
placeholderkeeps winning over the new pack'striggerPlaceholder. - Re-renders the trigger and the open popup.
- Also re-applies the pack-owned attributes
rerender()cannot reach: the filter input placeholder and its fallbackaria-label. - The clear button needs no such step:
rerender()rebuilds it, and the rebuild reads the new pack - unless acreateTriggerClearButtonEloverride returns the previous element, which then owns the label.
Parameters
| Parameter | Type |
|---|---|
uiTranslationPack |
Partial<LLSelectUiTranslationPack> |
Returns
void
Inherited from
Lifecycle
rerender()
rerender():
void
Defined in: base.ts:1517
Rebuild the trigger and (while open) the popup list from current state.
- Use it after mutating item OBJECTS in place (e.g.
users[0].name = 'X'). The library cannot detect that on its own. - It re-derives the display order (the
gatherGroupsgather). - While the filter is active, it re-runs the filter against the current item text.
- The refresh is purely visual: it does NOT fire
onChangeand does NOT runonItemsChanged. - Orchestrator: composes
renderTrigger+renderPopupList; touches no DOM directly.
Returns
void
Inherited from
destroy()
destroy():
void
Defined in: base.ts:1537
Tear down the instance: close the popup (which detaches every document /
window listener and the positioner), unwire labelEl (click listener
removed, a minted id removed), remove the library's class and
inline styles from the caller's mount element, and empty it. Idempotent.
The instance must not be used afterwards.
- REQUIRED before discarding an instance that might be OPEN (framework wrappers: call this on unmount) - skipping it there leaks the outside-click / focusout / scroll / resize listeners.
- Discarding a CLOSED instance without
destroy()leaks nothing; it only leaves the root class andoverflow-anchorstyle on the mount.
Returns
void
Inherited from
Constructor
new LLSelectSingle<
T,GroupKey,S>(targetEl,settings?):LLSelectSingle<T,GroupKey,S>
Defined in: single.ts:92
Build the control inside targetEl.
- Settings are resolved once here; missing fields get defaults.
- They are frozen afterwards, except
placeholderanduiTranslationPack, which have runtime setters; the rule is at LLSelectBaseSettings. - This plain form infers
Tfrom a typed callback insettingswhose signature containsT(itemToStringFn: (u: User) => ...). With no such callback, passTexplicitly:new LLSelectSingle<string>(...).
Parameters
| Parameter | Type |
|---|---|
targetEl |
HTMLElement |
settings? |
LLSelectSingleSettingsInput<T, GroupKey> |
Returns
LLSelectSingle<T, GroupKey, S>
Overrides
Constructor
new LLSelectSingle<
T,GroupKey,S>(targetEl,settings?,subclassSettings?):LLSelectSingle<T,GroupKey,S>
Defined in: single.ts:98
Subclass form. subclassSettings is the typed pass-through for subclasses
that extend the settings bag further; see LLSelectBase's S param.
Parameters
| Parameter | Type |
|---|---|
targetEl |
HTMLElement |
settings? |
LLSelectSettingsInputOf<S> |
subclassSettings? |
Omit<S, keyof LLSelectSingleSettings<T, GroupKey>> |
Returns
LLSelectSingle<T, GroupKey, S>
Overrides
LLSelectBase<T, GroupKey, S>.constructor
DOM elements
rootEl
readonlyrootEl:HTMLElement
Defined in: base.ts:875
The caller-passed mount element, now decorated as the select's root. Library does not replace this node, so the caller's original reference, id, and data-* attributes stay valid.
Inherited from
triggerEl
readonlytriggerEl:HTMLElement
Defined in: base.ts:885
The interactive trigger element. Receives focus, click, and keydown
events; carries aria-expanded, aria-controls, and
data-state="open|closed". Its role depends on the filter mode: combobox
while the filter is inactive (it then also hosts aria-activedescendant) and
button while a filterable popup is open (the filter input hosts
aria-activedescendant). See docs/llm/A11Y.md.
Inherited from
triggerContentEl
readonlytriggerContentEl:HTMLElement
Defined in: base.ts:892
Inner span inside the trigger where text/tags are written.
Subclasses' renderTriggerContent writes here so the sibling arrow slot
is preserved across re-renders.
Inherited from
popupEl
readonlypopupEl:HTMLElement
Defined in: base.ts:909
The outer popup wrapper. Has no ARIA role itself - it just hosts the
popup chrome (future: filter input, toggle-all control) and the inner
popupListEl. Hidden via the hidden attribute when closed; positioned
via inline styles by the positioner when open.
Inherited from
popupListEl
readonlypopupListEl:HTMLElement
Defined in: base.ts:917
The inner element with role="listbox", holding the item children.
Sits inside popupEl so siblings (filter input, toggle-all) can live
above it without violating ARIA's "listbox children must be options"
rule. The trigger's aria-controls points to this element.
Inherited from
popupHeaderEl
readonlypopupHeaderEl:HTMLElement|null
Defined in: base.ts:925
The pinned header container between the filter input and the listbox,
or null when no header content was built. No ARIA role; outside the
scroll area. Built once in the constructor (createPopupHeaderEl) and
kept until destroy(); the library never rebuilds or moves it.
Inherited from
popupFooterEl
readonlypopupFooterEl:HTMLElement|null
Defined in: base.ts:932
The pinned footer container at the bottom of the popup, after the
no-results message, or null when no footer content was built. Same
lifecycle as popupHeaderEl.
Inherited from
popupListPinnedLeadingRowsEl
readonlypopupListPinnedLeadingRowsEl:HTMLElement|null
Defined in: base.ts:950
The wrapper around the pinned leading rows, or null.
- Built once in the constructor when
popupListLeadingRowsPinnedistrue;nullotherwise. - A
divwithrole="presentation"and classpopupListPinnedLeadingRowsClass; the library setsposition: stickyandtop: 0on it inline. - In the listbox only while the leading rows exist. The library moves it
in and out on every list render. Its classes are yours to change after
new. data-edge-to-itemsis set on every list render:"true"when that render lists items,"false"when it lists none; absent before the first render.- It is a CSS hook for the themes: they draw the block's edge line only when it is true, so two blocks that touch draw no line between them.
Inherited from
popupListPinnedTrailingRowsEl
readonlypopupListPinnedTrailingRowsEl:HTMLElement|null
Defined in: base.ts:957
The wrapper around the pinned trailing rows, or null.
- Same contract as popupListPinnedLeadingRowsEl, for
popupListTrailingRowsPinned, withbottom: 0.
Inherited from
classIdMap
readonlyclassIdMap:LLSelectClassIdMap
Defined in: base.ts:962
Resolved class names and ids for this instance.
Inherited from
triggerValueEl
protectedreadonlytriggerValueEl:HTMLElement
Defined in: base.ts:901
Hidden root-level span (sibling of the trigger) mirroring the current
value as plain text. Kept in sync by commitTriggerContentToDom;
referenced by the filterable-mode aria-labelledby chain (see
classIdMap.triggerValueId). Outside the trigger so
triggerEl.textContent stays exactly the visible content.
Inherited from
Subclassing: reactions
onOpened()
protectedonOpened():void
Defined in: base.ts:1753
Subclass hook: called once after the popup finishes opening. Default no-op.
The onOpen setting fires alongside this (both run) - hook for subclass
logic, setting for consumer notification.
Returns
void
Inherited from
onClosed()
protectedonClosed():void
Defined in: base.ts:1758
Subclass hook: called once after the popup finishes closing. Pairs with the onClose setting (both run).
Returns
void
Inherited from
onChosenChanged()
protectedonChosenChanged():void
Defined in: base.ts:1765
Subclass hook: called after the chosen state actually changed, right
before the variant's onChange setting fires (hook first, both run -
same pairing as onOpened / onClosed). Default no-op.
Returns
void
Inherited from
onPopupListActionRowActivated()
protectedonPopupListActionRowActivated(row):void
Defined in: base.ts:2522
Subclass hook: an action row was activated.
- The library calls it on Enter, on Space while the filter is inactive,
and on click, after the disabled re-check, as a user change. You never
call it.
rowcomes from the library: the activated entry. - Default calls the entry's
onActivate. The library changes nothing else: choosing and closing are the entry's job. - Override to react before or after: do your work, then call
super.onPopupListActionRowActivated(row). Without that call the entry'sonActivatenever runs.
Parameters
| Parameter | Type |
|---|---|
row |
LLSelectPopupListActionRow |
Returns
void
Inherited from
withUserChangeSource()
protectedwithUserChangeSource<R>(fn):R
Defined in: base.ts:2582
Run fn with chosen-state changes attributed to the user. The library
wraps exactly its pointer / keyboard entry points with it - option
activation, the tag remove button, the clear button, the choose-all row;
everything else reports 'api'.
Type Parameters
| Type Parameter |
|---|
R |
Parameters
| Parameter | Type |
|---|---|
fn |
() => R |
Returns
R
Inherited from
onChooseAllRowActivated()
protectedonChooseAllRowActivated():void
Defined in: base.ts:2597
Subclass hook: the choose-all row was activated - Enter while it is focused (subclasses also wire their row's click handler to this). Default no-op.
Returns
void
Inherited from
onItemActivated()
protectedonItemActivated(item):void
Defined in: single.ts:186
Pick this item as the chosen item and close the popup.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
void
Overrides
onItemsChanged()
protectedonItemsChanged():void
Defined in: single.ts:247
Re-match the chosen item against the new list after setItems.
- If the list no longer holds it (by
compareFn), it is dropped andonChangefires. - If the list holds a compareFn-equal but DIFFERENT object (
track bystyle reload: same key, fresh fields), the stored reference is swapped to the list's object. The logical value did not change, soonChangedoes not fire. - The trigger content re-renders after every
setItems, because a customcreateTriggerContentElFnreceivesitems. - The arrow re-renders only when the chosen item is dropped, because that runs the whole trigger.
Returns
void
Overrides
Subclassing: rendering
renderTrigger()
protectedrenderTrigger():void
Defined in: base.ts:1810
Orchestrator: composes the clear-button rebuild + renderTriggerContent +
renderTriggerArrow to (re)build the whole trigger from state; touches no
DOM directly. Subclasses normally override renderTriggerContent,
not this.
- Runs on every change of the chosen value, the placeholder or the pack.
rerender()runs it too.- While
clearableis on, the first run builds the clear button and every later run swaps it for whatevercreateTriggerClearButtonElreturns: a fresh button from the base implementation, like the arrow. An override may return the previous element; it is then kept in place. - If the button is rebuilt and the old one held focus - on it or inside its icon - the rebuilt BUTTON gets it.
- If the builder returned the same element, nothing was rebuilt, and focus goes back to the node that held it, if that node is still inside the button and can take focus; otherwise focus stays on the button.
setItemsrunsrenderTriggerContentalone, because only the content reads the list (the multiple count total, a customcreateTriggerContentElFn'sitems).- A
setItemsthat drops the chosen entry runs the whole trigger. - Runs once from the
LLSelectSingle/LLSelectMultipleconstructor, right aftersuper(). - On that first run a FURTHER subclass's own fields are still
undefined: JS runs a subclass's field initializers only after its super constructor returns (virtual-call-in-constructor). An override of a trigger method (renderTriggerContent, or acreate*Elit calls) that reads such a field seesundefinedthere. - The recipe: put construction-time configuration in the typed
subclassSettingsconstructor param.this.settingsis complete before any construction code runs. - For genuine instance state, tolerate defaults during construction, or call
rerender()at the end of your own constructor. - The popup-list methods do NOT run here; they wait for
open(). See DESIGN.md "Customization model".
Returns
void
Inherited from
commitTriggerContentToDom()
protectedcommitTriggerContentToDom(content,plainTextValue?):void
Defined in: base.ts:1833
Write the trigger's content slot (triggerContentEl), replacing whatever
was there; the sibling arrow slot is untouched. The single DOM-writing
primitive behind every renderTriggerContent path.
string-> set astextContent(plain text, NOT parsed as HTML). Used for the default placeholder /itemToStringtext / count summary.HTMLElement-> inserted as-is viareplaceChildren; caller owns the node. Used for whatever thecreateTriggerContentElFnsetting returned.- Also mirrors the value into the hidden
triggerValueEl(the accessible name source): the string itself, elseplainTextValue, else the element'stextContent. PassplainTextValuewhenever the element contains labelled controls (tag remove buttons) or icon-only content - the mirror is what AT announces as the field's value. Called byrenderTriggerContent- the base default and theLLSelectSingle/LLSelectMultipleoverrides.
Parameters
| Parameter | Type |
|---|---|
content |
string | HTMLElement |
plainTextValue? |
string |
Returns
void
Inherited from
syncEmptyStateToDom()
protectedsyncEmptyStateToDom():void
Defined in: base.ts:1850
Mirror the empty/filled state onto the trigger's data-empty attribute
("true" when isEmpty(), else "false"). A CSS / AT styling hook,
independent of the rendered content. Called by the subclass
renderTriggerContent overrides.
Returns
void
Inherited from
createTriggerArrowContentEl()
protectedcreateTriggerArrowContentEl(state):HTMLElement|SVGElement|null
Defined in: base.ts:1896
Trigger arrow element for the given open state.
- Default reads
createTriggerArrowContentElFn;null(setting unset, or returned for a state) = no arrow for that state. - Override only when extending; for one-off arrows pass the setting.
Mirrors
createTriggerClearButtonEl/createItemContentEl.
Parameters
| Parameter | Type |
|---|---|
state |
{ isOpened: boolean; } |
state.isOpened |
boolean |
Returns
HTMLElement | SVGElement | null
Inherited from
renderPopupList()
protectedrenderPopupList():void
Defined in: base.ts:1929
Orchestrator: composes createItemEl (build) + computePopupSegments +
commitPopupSegmentsToDom (write) to rebuild the popup list from
getVisibleItems(); touches no DOM directly. Called by open() and by
setItems() while open. Also clamps focusedIndex if the list shrank and
re-applies focus visuals.
- Extend it by wrapping: override, do your work before or after, then
call
super.renderPopupList(). The ui-select bridge frees its row scopes this way. Or override one of the methods it calls throughthis:createItemEl,createPopupListChooseAllRowEl,createPopupListLeadingActionRowEl/createPopupListTrailingActionRowEl,itemToGroupKey,getVisibleItems. - Its other internals stay private on purpose. They re-establish the
itemEls[i] <-> getVisibleItems()[i]alignment as one unit, so no subclass can leave keyboard nav oraria-activedescendanthalf-synced.
Returns
void
Inherited from
createGroupEl()
protectedcreateGroupEl(key,index,items,itemEls):HTMLElement
Defined in: base.ts:2064
Build the whole DOM element for one group container.
- The library calls it, once per group of the current render, on every list render. You never call it yourself.
- All four params come from the library. Forward them to
superunchanged. indexis the group's position among this render's groups, counted from 0. It only mints the group id. It is not an identity: it changes whenever the visible list changes.- To change only the label's content, do not override this. Pass the
createGroupLabelContentElFnsetting instead. - To change the element itself, override it, call
super.createGroupEl(...), and edit the returned element. Keep theroleandaria-labelthe base set. - Internals: the base sets the id,
role="group"named bygroupKeyToString(aria-label), anaria-hiddenvisible label element filled from createGroupLabelContentEl (else the plain label text), then the group's item elements;aria-disabled+data-disabledwhen the group is disabled.
Parameters
| Parameter | Type | Description |
|---|---|---|
key |
GroupKey |
the group's key, supplied by the library |
index |
number |
the group's position among this render's groups, supplied by the library |
items |
readonly T[] |
the group's items, supplied by the library (for counts / rich content) |
itemEls |
HTMLElement[] |
the group's already-built option elements, supplied by the library |
Returns
HTMLElement
Inherited from
createGroupLabelContentEl()
protectedcreateGroupLabelContentEl(key,itemsInGroup):HTMLElement|null
Defined in: base.ts:2098
Group label -> its visible content element (icon / count badge / rich
markup). Mirrors createItemContentEl.
- Default reads
createGroupLabelContentElFn, elsenullsocreateGroupEluses plain text fromgroupKeyToString. - The group's accessible name stays
groupKeyToString(containeraria-label); this fills only the visible,aria-hiddenlabel content. - Override only when extending; for one-off rich labels pass the setting.
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
itemsInGroup |
readonly T[] |
Returns
HTMLElement | null
Inherited from
replacePopupListItemElInDom()
protectedreplacePopupListItemElInDom(item):void
Defined in: base.ts:2112
Re-render a single item's element in place instead of rebuilding the whole popup list. The DOM work is O(1) regardless of list size, so flipping one selection in a 10k-item list does not recreate 10k nodes (the lookup to find the item is O(n), but that is a cheap comparison loop next to DOM mutation). No-op if the popup is closed or the item is not in the current list. Used by multi-select toggle.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
void
Inherited from
createItemContentEl()
protectedcreateItemContentEl(item):HTMLElement|null
Defined in: base.ts:2222
Item -> the visible content of its list row (icon + text etc.).
- Default reads
createItemContentElFn, elsenullsocreateItemEluses the plain-text default fromitemToString. - Override only when extending; for one-off rich content pass the setting.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
HTMLElement | null
Inherited from
createPopupListLeadingActionRowEl()
protectedcreatePopupListLeadingActionRowEl(row,index):HTMLElement
Defined in: base.ts:2427
Build the whole DOM element for one leading action row (above the items).
- The library calls it, once per entry of
popupListLeadingActionRows, on every list render and after every chosen change. You never call it. - Both params come from the library. Forward them to
superunchanged.rowis the entry;indexis its position in that array, counted from 0, used to mint the id. It is not an identity. - To change only what the row shows, do not override this: give the entry
a
createContentElFn. - To change the element itself, override it, call
super.createPopupListLeadingActionRowEl(row, index), and edit the returned element. Keep theidandrole; put no focusable control inside. - Internals: a
divwithrole="option", the id<listbox id>-action-row-leading<index>,itemClasspluspopupListActionRowClass, the visible content from createPopupListActionRowContentEl (elsetextContentfromtextFn),aria-label=textFn()when the content is custom, and eitheraria-disabledplus the disabled class (isPopupListActionRowDisabled) or a click handler that focuses the row, then runs onPopupListActionRowActivated. Noaria-selected: a command has no selected state.
Parameters
| Parameter | Type | Description |
|---|---|---|
row |
LLSelectPopupListActionRow |
the entry, supplied by the library |
index |
number |
the entry's position in popupListLeadingActionRows, supplied by the library |
Returns
HTMLElement
Inherited from
createPopupListTrailingActionRowEl()
protectedcreatePopupListTrailingActionRowEl(row,index):HTMLElement
Defined in: base.ts:2450
Build the whole DOM element for one trailing action row (below the items).
- The library calls it, once per entry of
popupListTrailingActionRows, on every list render and after every chosen change. You never call it. - Both params come from the library. Forward them to
superunchanged.rowis the entry;indexis its position in that array, counted from 0, used to mint the id. It is not an identity. - To change only what the row shows, do not override this: give the entry
a
createContentElFn. - To change the element itself, override it, call
super.createPopupListTrailingActionRowEl(row, index), and edit the returned element. Keep theidandrole; put no focusable control inside. - Internals: identical to createPopupListLeadingActionRowEl
except the id,
<listbox id>-action-row-trailing<index>.
Parameters
| Parameter | Type | Description |
|---|---|---|
row |
LLSelectPopupListActionRow |
the entry, supplied by the library |
index |
number |
the entry's position in popupListTrailingActionRows, supplied by the library |
Returns
HTMLElement
Inherited from
createPopupListActionRowContentEl()
protectedcreatePopupListActionRowContentEl(row):HTMLElement|null
Defined in: base.ts:2493
An action row's visible content element.
- The library calls it from the row builders, once per row render. You
never call it.
rowcomes from the library. - Default reads the entry's
createContentElFn;null(unset, or returned) = plain text fromtextFn. - Override only when extending; for one-off content give the entry a
createContentElFn.
Parameters
| Parameter | Type |
|---|---|
row |
LLSelectPopupListActionRow |
Returns
HTMLElement | null
Inherited from
replacePopupListActionRowElsInDom()
protectedreplacePopupListActionRowElsInDom():void
Defined in: base.ts:2538
Rebuild every rendered action row in place, so textFn / disabledFn
reflect the current state; the row holding the active option keeps it.
- The library calls it after every chosen change, right after
onChangefired (a row's text may read what the handler wrote). Subclasses may call it after a state change of their own. - No-op while closed, or when both row arrays are empty - instances without rows pay nothing.
- O(rows) DOM work; the item rows are untouched.
Returns
void
Inherited from
createPopupListChooseAllRowEl()
protectedcreatePopupListChooseAllRowEl():HTMLElement|null
Defined in: base.ts:2573
Optional non-item role="option" row placed first, at the TOP of the listbox:
inside the arrow-key ring (ArrowUp from the first item reaches it, Home
lands on it, up-actions clamp there) but never inside itemEls, so the
itemEls[i] <-> getVisibleItems()[i] alignment is untouched. Rebuilt on
every renderPopupList. Base default: null = no choose-all row.
LLSelectMultiple builds its choose-all row here (chooseAllRow setting).
Returns
HTMLElement | null
Inherited from
replaceChooseAllRowElInDom()
protectedreplaceChooseAllRowElInDom():void
Defined in: base.ts:2652
Rebuild the choose-all row in place (tri-state / text refresh) without
touching the item elements - O(1) DOM work, mirroring
replacePopupListItemElInDom. Falls back to a full renderPopupList
when the row becomes inapplicable (builder returns null). No-op while
closed or when no choose-all row is rendered.
Returns
void
Inherited from
createTriggerClearButtonEl()
protectedcreateTriggerClearButtonEl():HTMLElement
Defined in: base.ts:3047
Build the clear (x) button for the clearable trigger slot.
- The library owns the button, its click (stops propagation so it never
toggles the popup, then
clearSelection; a no-op while the control is disabled) and itsaria-label(text fromuiTranslationPack.triggerClearButtonAriaLabel). createTriggerClearButtonContentElFnoptionally fills the icon; else the theme's CSS glyph draws it.- The theme hides the button via
data-emptywhile nothing is chosen. - It runs on every trigger render (
renderTrigger). - The first run builds the button.
- For
LLSelectSingle/LLSelectMultipleand their subclasses, that first run is the variant constructor's render, right aftersuper(), so it happens before a FURTHER subclass's field initializers. - A direct
LLSelectBasesubclass gets the button on its first trigger render (its ownrenderTrigger()call, orrerender()/setPlaceholder); until then the trigger is unrendered and there is no button. - Every later run (a value change,
setPlaceholder,setUiTranslationPack,rerender()) swaps the button in place, unless this method returns the previous element - then it stays in place. - The base implementation returns a fresh element each run, so, like the arrow, nothing put on it from outside survives a render; customize it here.
- An override that returns the same element every time owns everything
the rebuild would otherwise refresh on it, including its
aria-labelaftersetUiTranslationPack. - An override that reads subclass fields calls
rerender()at the end of its constructor, like every other trigger method.
Returns
HTMLElement
Inherited from
createTriggerClearButtonContentEl()
protectedcreateTriggerClearButtonContentEl():HTMLElement|SVGElement|null
Defined in: base.ts:3174
Clear button's visible content (its x icon).
- Default reads
createTriggerClearButtonContentElFn;null(setting unset, or returned) = no icon - the theme's CSS glyph draws the x. - Override only when extending; for one-off icons pass the setting.
Returns
HTMLElement | SVGElement | null
Inherited from
createPopupListNoResultsContentEl()
protectedcreatePopupListNoResultsContentEl(query):HTMLElement|null
Defined in: base.ts:3356
The no-results message's visible content (rich empty-state).
- Default reads
createPopupListNoResultsContentElFn;null(setting unset, or returned) = plain text fromuiTranslationPack.popupListNoResults. - Override only when extending; for one-off content pass the setting.
Parameters
| Parameter | Type |
|---|---|
query |
string |
Returns
HTMLElement | null
Inherited from
createPopupHeaderEl()
protectedcreatePopupHeaderEl():HTMLElement|null
Defined in: base.ts:3376
Build the pinned header container between the filter input and the listbox.
- The library calls it once, inside the constructor. You never call it.
- It takes no params. The default asks createPopupHeaderContentEl
for content;
nullcontent = no container, andpopupHeaderElstaysnull. - To supply content without subclassing, pass
createPopupHeaderContentElFn. - To change the container itself, override it: call
super.createPopupHeaderEl()and edit the returned element, or return your owndiv. Returning non-null builds the slot even without the setting. Keep it role-free: it is not part of the listbox. - Internals: the base builds a
divwithclassIdMap.popupHeaderClassand inlineflex: none(the popup is a flex column and only the listbox may flex), then appends the content.
Returns
HTMLElement | null
Inherited from
createPopupHeaderContentEl()
protectedcreatePopupHeaderContentEl():HTMLElement|null
Defined in: base.ts:3390
The pinned header's content element.
- The library calls it once, from createPopupHeaderEl, inside the constructor. You never call it.
- Default calls
createPopupHeaderContentElFnwith a LLSelectConstructionContext;null(setting unset, or returned) = no header at all. - Override only when extending; for one-off content pass the setting.
Returns
HTMLElement | null
Inherited from
createPopupFooterEl()
protectedcreatePopupFooterEl():HTMLElement|null
Defined in: base.ts:3410
Build the pinned footer container at the bottom of the popup.
- The library calls it once, inside the constructor. You never call it.
- It takes no params. The default asks createPopupFooterContentEl
for content;
nullcontent = no container, andpopupFooterElstaysnull. - To supply content without subclassing, pass
createPopupFooterContentElFn. - To change the container itself, override it: call
super.createPopupFooterEl()and edit the returned element, or return your owndiv. Returning non-null builds the slot even without the setting. Keep it role-free: it is not part of the listbox. - Internals: the base builds a
divwithclassIdMap.popupFooterClassand inlineflex: none(only the listbox may flex), then appends the content.
Returns
HTMLElement | null
Inherited from
createPopupFooterContentEl()
protectedcreatePopupFooterContentEl():HTMLElement|null
Defined in: base.ts:3424
The pinned footer's content element.
- The library calls it once, from createPopupFooterEl, inside the constructor. You never call it.
- Default calls
createPopupFooterContentElFnwith a LLSelectConstructionContext;null(setting unset, or returned) = no footer at all. - Override only when extending; for one-off content pass the setting.
Returns
HTMLElement | null
Inherited from
renderTriggerContent()
protectedrenderTriggerContent():void
Defined in: single.ts:152
Orchestrator: composes syncEmptyStateToDom + commitTriggerContentToDom
to (re)build the trigger from state; touches no DOM directly.
createTriggerContentElFnis tried first; if it returnsnullor is unset, the default applies.- The default is the chosen item's string, or the placeholder when nothing is chosen.
Returns
void
Overrides
createItemEl()
protectedcreateItemEl(item,index):HTMLElement
Defined in: single.ts:176
Mark the chosen option aria-selected="true", the rest "false" (APG select-only).
Parameters
| Parameter | Type |
|---|---|
item |
T |
index |
number |
Returns
HTMLElement
Overrides
Subclassing: semantics
itemToString()
protecteditemToString(item):string
Defined in: base.ts:2210
Map an item to its display string. The library calls this everywhere it needs an item's text: list rows, the single trigger text, default filter.
- Default reads the
itemToStringFnsetting, elseString(item). - Configure via
itemToStringFn(no subclass needed). - Override only when extending (a new select type); your override replaces
the default. For HTML content, subclass
createItemEl.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
string
Inherited from
isItemEffectivelyDisabled()
protectedisItemEffectivelyDisabled(item):boolean
Defined in: base.ts:2236
Whether item is effectively disabled - by itemDisabledFn, or because
its group is disabled (groupDisabledFn). Group-disabled layers on top,
so every item-disabled behavior (no selection, keyboard skip, aria)
covers grouped items with no extra code. False when neither applies.
The whole-control disabled state (isDisabled()) is a separate layer,
not part of this answer.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
boolean
Inherited from
itemToGroupKey()
protecteditemToGroupKey(item):GroupKey|null
Defined in: base.ts:2255
Map an item to its group key, or null when it belongs to no group.
The authoritative method: rendering, the gatherGroups gather, and the
disabled layer all resolve keys through this method, so an override
drives them all - returning keys turns grouping on even with the setting
unset (all-null keys = flat list). An override reading external state
must call rerender() after that state changes (same contract as
mutating item objects).
- Default reads
itemToGroupKeyFn, elsenull(grouping off). - Override only when extending; configure via the setting.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
GroupKey | null
Inherited from
groupKeyToString()
protectedgroupKeyToString(key):string
Defined in: base.ts:2265
Map a group key to its label display text.
- Default reads
groupKeyToStringFn, elseString(key).
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
Returns
string
Inherited from
isGroupDisabled()
protectedisGroupDisabled(key):boolean
Defined in: base.ts:2274
Whether the whole group key is disabled per groupDisabledFn (false when unset).
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
Returns
boolean
Inherited from
isPopupListActionRowDisabled()
protectedisPopupListActionRowDisabled(row):boolean
Defined in: base.ts:2505
Whether an action row is disabled right now.
- The library calls it from the row builders (once per row render) and
again at activation. You never call it.
rowcomes from the library. - Default reads the entry's
disabledFn;null/ omitted = never disabled.
Parameters
| Parameter | Type |
|---|---|
row |
LLSelectPopupListActionRow |
Returns
boolean
Inherited from
matchesQuery()
protectedmatchesQuery(item,query):boolean
Defined in: base.ts:3283
Per-item match predicate for the filter input.
- Default reads
filterFn; else case-insensitive substring onitemToString. - Override only when extending (subclass-wide custom matching); for a one-off match rule pass the setting.
Parameters
| Parameter | Type |
|---|---|
item |
T |
query |
string |
Returns
boolean
Inherited from
isEmpty()
protectedisEmpty():boolean
Defined in: single.ts:168
No selection iff chosenItem is unset. Drives the trigger's data-empty.
Returns
boolean
Overrides
clearSelection()
protectedclearSelection():void
Defined in: single.ts:195
Clear button empties the single selection to undefined.
Returns
void
Overrides
Subclassing: focus
findNextEnabledIndex()
protectedfindNextEnabledIndex(start,step,list):number
Defined in: base.ts:2285
First enabled index scanning from start (inclusive) by step (+1 / -1).
Returns -1 if no enabled item lies in that direction. Used to skip disabled
items during keyboard nav and initial focus.
Parameters
| Parameter | Type |
|---|---|
start |
number |
step |
number |
list |
readonly T[] |
Returns
number
Inherited from
setFocusedIndex()
protectedsetFocusedIndex(index):void
Defined in: base.ts:2617
Move keyboard focus to the item at index. The value is clamped to
[-1, items.length-1]; pass -1 to clear focus. Updates the focused
class, aria-activedescendant, and scrolls the item into view. No-op
if the clamped value equals the current focused index.
Parameters
| Parameter | Type |
|---|---|
index |
number |
Returns
void
Inherited from
focusChooseAllRow()
protectedfocusChooseAllRow():boolean
Defined in: base.ts:2635
Move keyboard focus onto the choose-all row. Returns whether the row is now
focused (false = none is rendered, nothing changed). The item focus is
cleared (focusedIndex becomes -1). Protected so a subclass can wire its
choose-all row's click to focus-then-activate (mirroring how item clicks
call setFocusedIndex before onItemActivated) and use it in
focusInitial (the choose-all row is the listbox's FIRST option).
Returns
boolean
Inherited from
focusInitial()
protectedfocusInitial():void
Defined in: single.ts:204
On open, focus the chosen item (if present and enabled), else the first
enabled item. Indices are into getVisibleItems() (the rendered list).
Returns
void
Overrides
computeTypeaheadClosedStartIndex()
protectedcomputeTypeaheadClosedStartIndex(list):number
Defined in: single.ts:226
Closed-state typeahead searches relative to the CHOSEN item, like a
native <select>: typing its initial cycles to the next match.
- Returns
-1when nothing is chosen, or the chosen item left the list; the search then starts from the top.
Parameters
| Parameter | Type |
|---|---|
list |
readonly T[] |
Returns
number
Overrides
State (protected)
settings
protectedreadonlysettings:S
Defined in: base.ts:972
Resolved settings (defaults applied) - ONE bag for the whole hierarchy.
Typed by the class's S param: a subclass that extends the settings
passes its resolved extra fields through the constructor's
subclassSettings param, and this field is S with no re-typing
(see LLSelectSingle / LLSelectMultiple).
Inherited from
items
protecteditems:T[] =[]
Defined in: base.ts:983
Current item list. Defensive copy of what setItems was given.
Inherited from
focusedIndex
protectedfocusedIndex:number=-1
Defined in: base.ts:992
Position in getVisibleItems() (the rendered list, not items) of the
currently keyboard-focused item, or -1 when nothing is focused (closed
popup, or no items).
Inherited from
changeSource
protectedchangeSource:LLSelectChangeSource='api'
Defined in: base.ts:1002
Who the change being applied right now is attributed to; the variants'
onChange firing reads it. Set to 'user' by withUserChangeSource
and consumed (reset to 'api') by the first onChange fired, so a
nested api-driven change inside an onChange handler reports 'api'.
Inherited from
chosenItem
protectedchosenItem:T|undefined=undefined
Defined in: single.ts:80
Currently chosen item, or undefined if none.
Settings
Base
LLSelectOutsideClickBehavior
LLSelectOutsideClickBehavior =
"pass-through"|"block"
Defined in: base.ts:30
What happens when the user clicks outside an open popup.
'pass-through'(default): close the popup; the outside click still triggers its normal action (button click, link navigation, etc.).'block': close the popup only; the outside click is swallowed so no underlying handler or default action fires. Avoids accidental side effects when the user only intended to dismiss the dropdown.
LLSelectBaseSettings
Defined in: base.ts:127
Resolved (defaults applied) settings shared by all select variants.
Subclasses (LLSelectSingle, LLSelectMultiple) extend this with their
mode-specific options such as onChange.
Settings are frozen after the constructor. What still changes at runtime:
- State changes by method, and never was a setting: the items
(
setItems), the chosen value (setChosenItem/setChosenItems),disabled(setDisabled). - Two settings have a setter, because they are text:
uiTranslationPack(setUiTranslationPack) andplaceholder(setPlaceholder). - Every other setting is fixed for the instance's lifetime.
- To change a fixed setting, build a new instance. One build takes about 0.2 ms.
- If a setting must vary at runtime, use its function form where one
exists.
filterable: (items) => booleanis re-evaluated on every open (and consulted by closed-state typeahead - see the setting).
Extended by
Type Parameters
| Type Parameter | Default type |
|---|---|
T |
- |
GroupKey |
string |
Items
compareFn
compareFn: (
a,b) =>boolean
Defined in: base.ts:202
Equality predicate for item values - return true when a and b are the
same item.
- Required for non-primitive
T. The default compares by identity:===, except thatNaNequalsNaN(SameValueZero, the same ruleSetuses), so every code path agrees on what "the same item" means. - Used for selection, dedup, and matching the chosen item back to the list.
- Symmetric: do not depend on which argument is the candidate vs the existing item.
Parameters
| Parameter | Type |
|---|---|
a |
T |
b |
T |
Returns
boolean
itemToStringFn
itemToStringFn: ((
item) =>string) |null
Defined in: base.ts:460
Item -> display string, without subclassing.
null(default) =String(item).- Read by the
itemToStringmethod's default; used for list text, the single trigger text, the option's accessible name, and the default filter. Inserted astextContent(plain text, NOT parsed as HTML). - For rich content (icons etc.), pass
createItemContentElFn.
createItemContentElFn
createItemContentElFn: ((
item) =>HTMLElement|null) |null
Defined in: base.ts:496
Item -> the visible content ELEMENT of its list row, without subclassing.
- Return an
HTMLElementand the library inserts it as-is (you own the node); it becomes the row's visible content. null= plaintextContentfromitemToString. This is the default, both when the setting is unset and when your function returnsnullfor a particular item.- Fills the VISIBLE content only. You never touch
aria-*: when this returns an element the library sets the option'saria-labelfromitemToString, so the accessible name + match text stay owned byitemToStringno matter what you render (icon-only, reordered, ...). To make the spoken/matched text differ from the visible content, set the two independently:itemToStringFnfor the name/matching,createItemContentElFnfor the look. - For full control of the option element (tag / wiring), subclass
createItemElinstead. - Runs per rendered row per render, and re-runs whenever a row is
rebuilt: open, filter,
setItems, AND chosen-state changes (both modes replace the affected rows in place while the popup is open). Content that reads selection state (e.g. a checkmark on the chosen row viacreateCheckmarkSvgEl) therefore stays fresh; keep the function cheap.
Example
// List shows an icon + the item text; screen readers announce just that text.
itemToStringFn: (lang) => lang.name,
createItemContentElFn: (lang) => {
const row = document.createElement('span')
const icon = document.createElement('i')
icon.className = `mdi mdi-${lang.icon}`
icon.setAttribute('aria-hidden', 'true') // decorative
row.append(icon, lang.name)
return row
}
Accessible name
ariaLabel
ariaLabel:
string|null
Defined in: base.ts:161
Accessible name of the field, like the <label> text of a native
<select> (e.g. 'Country').
- Applied to the trigger, the popup listbox, and (while the filter is active)
the filter input; per-mode wiring:
docs/llm/A11Y.md"Accessible name". - The name resolves by the FIRST set rung, mirroring the W3C
accessible-name computation order:
ariaLabelledBy.ariaLabel(this setting).labelEl- its element's id becomes the resolvedariaLabelledBy.- None set: the field is unnamed. A combobox requires a name
(WAI-ARIA 1.2), so one
console.warnper page reports the first offender.
null(default): this rung is skipped. An empty or whitespace-only string counts as unset too - the accname computation skips a blankaria-label, and so does the ladder.
ariaLabelledBy
ariaLabelledBy:
string|null
Defined in: base.ts:174
Space-separated DOM id(s) of the visible label element(s) naming the
field; forwarded as aria-labelledby to the same elements as ariaLabel.
- Prefer this over
ariaLabelwhen a visible label element exists: the spoken name then always matches the visible text. null(default): not forwarded; seeariaLabelfor the naming requirement. An empty or whitespace-only string counts as unset too, same asariaLabel.- Rung 1 of the resolution order (the numbered list at
ariaLabel): it wins whenever set, matching the ARIA name computation.
labelEl
labelEl:
HTMLElement|null
Defined in: base.ts:190
The widget's visible label element - the one foreign element the library
touches. Emulates native <label for> (which cannot target these divs)
in both directions:
- clicking it focuses the trigger (focus ONLY; native
<select>does not open on label click, neither does this); - it feeds the accessible name as rung 3 of the resolution order (the
numbered list at
ariaLabel): with neither aria setting given, the label's id becomes the resolvedariaLabelledBy(an id is minted fromclassIdMap.labelIdif the element has none) - a live reference, so later label text changes stay correct. null= no label element; the name ladder just skips this rung.destroy()removes the click listener and a minted id.
Events
onOpen
onOpen: (() =>
void) |null
Defined in: base.ts:571
Fired right after the popup opens. An open() call that does not actually
open the popup (already open, a disabled control, or a trigger scrolled out
of view or clipped) does not fire it. Fires in ADDITION to the protected
onOpened hook - the setting is for consumers, the hook for subclasses;
both run. null (default) = nothing.
onClose
onClose: (() =>
void) |null
Defined in: base.ts:577
Fired right after the popup closes. A no-op close() does not fire it.
Additive with the protected onClosed hook, like onOpen.
onFilterQueryChange
onFilterQueryChange: ((
query) =>void) |null
Defined in: base.ts:591
Called after the filter text changed and the list was re-rendered.
- Fires on typing, when an IME composition ends, and when Esc clears a
non-empty query.
queryis the new text. - Does not fire when the text stays the same, when
close()clears the query (useonClose), whenopen()starts with an empty query, or onsetItems()/rerender(). - Runs after the list is rebuilt, so
getVisibleItems()already reflects the new text. Rewrite a header count from here, fromonOpenand fromonChange. null(default): nothing is called.
Trigger
placeholder
placeholder:
string
Defined in: base.ts:142
Text shown in the trigger when nothing is selected. App copy: an explicit
value always wins; when unset, the locale default
uiTranslationPack.triggerPlaceholder is used ('Please select' in English).
createTriggerArrowContentElFn
createTriggerArrowContentElFn: ((
state) =>HTMLElement|SVGElement|null) |null
Defined in: base.ts:216
The trigger arrow slot's content ELEMENT (typically a dropdown chevron or
triangle). Called whenever the arrow may need to change - including on
every open/close - so the returned element can vary with isOpened.
- fn returns
null- no arrow for that state. - setting is
null(default) - the library adds nothing to the arrow slot.
clearable
clearable:
boolean
Defined in: base.ts:241
Whether the trigger shows a clear (x) button that empties the selection.
- Default
false. - Clearing sets the empty value:
undefinedfor a single select,[]for a multiple. It goes through the normal setters, soonChangefires with that empty value. There is no separate clear event. - The empty value is not configurable, and no library makes it so:
"nothing chosen" already exists before the first choice, so the value
types carry
undefinedeither way. - If your model is a plain type like
stringand must never holdundefined, pick one of these:- Add a real "none" item (for example
''shown as "(none)") and skipclearable. The model then staysstringafter the first choice, exactly like a native<select>with a placeholder option. - Keep
clearableand coerce inonChange:item ?? ''.
- Add a real "none" item (for example
- "Clear" means back to empty and the placeholder, never "back to some
default option". If you want a default instead, set it yourself in
onChange. - The button sits in its OWN trigger slot (like the arrow, so it never
collides with
createTriggerContentElFn), istabindex="-1", and carries anaria-label. The theme hides it viadata-emptywhile nothing is selected.
createTriggerClearButtonContentElFn
createTriggerClearButtonContentElFn: (() =>
HTMLElement|SVGElement|null) |null
Defined in: base.ts:248
Content ELEMENT of the clear button (its x icon), mirroring createTriggerArrowContentElFn.
null (default) = the theme's CSS glyph. The library always owns the button,
its click (clears + stops propagation) and aria; this only fills the icon.
Filtering
filterable
filterable:
boolean| ((items) =>boolean)
Defined in: base.ts:265
Whether the popup includes a filter input.
false(default): never.true: always.- Predicate
(items) => boolean: conditional - evaluated against the CURRENT full item list each time the popup OPENS (never mid-open; asetItemscrossing the threshold applies on the next open). E.g.filterable: (items) => items.length > 10. A printable key pressed while CLOSED also calls the predicate, read-only, to decide whether prefix typeahead may take the key - keep it cheap and side-effect free. The ARIA mode follows the evaluated value per open cycle: active = triggerrole="button", focus moves to the input; inactive = exactly likefilterable: false(trigger staysrole="combobox", focus stays on the trigger). Seedocs/llm/A11Y.mdanddocs/llm/DESIGN.md.
filterFn
filterFn: ((
item,query) =>boolean) |null
Defined in: base.ts:287
Predicate used by the filter input; return true to keep the item.
null (default) means the built-in case-insensitive substring match
against the item's resolved text (itemToStringFn / itemToString).
Pass a custom function for fuzzy / domain-specific matching.
queryis the RAW input value: not trimmed and not lower-cased. Normalize it yourself (the built-in lower-cases both sides; it does not trim).- Not called while the query is empty (an empty box shows every item), but a
whitespace-only query (e.g.
" ") does call it.
createPopupListNoResultsContentElFn
createPopupListNoResultsContentElFn: ((
query) =>HTMLElement|null) |null
Defined in: base.ts:304
The no-results message's visible content ELEMENT, without subclassing.
Mirrors createItemContentElFn: the library owns the message container
(role="status", class, show/hide), this fills its content only.
queryis the current filter query (''when the filter is inactive or the list is simply empty), so "Nothing matches" is possible. - Return an
HTMLElement: inserted as the content (you own it; include real text - the status region announces its TEXT content). null(setting default, or returned): plain text fromuiTranslationPack.popupListNoResults. Re-evaluated every time the message is shown (the query may differ). The DOM is refreshed only when the resolved TEXT changes - the status region is keyed on text so it announces once, not per keystroke - so rich content whose visible markup varies while its text stays constant is not re-rendered.
Grouping
itemToGroupKeyFn
itemToGroupKeyFn: ((
item) =>GroupKey|null) |null
Defined in: base.ts:507
Item -> its group's key (identity), enabling optgroup rendering.
null(setting, default): grouping off - flat list, no labels.- fn returns
null: this item is in no group; renders ungrouped. - Contiguous items with an equal key (per
groupKeyCompareFn) form one group. By default non-contiguous data is first gathered into display order (gatherGroups); withgatherGroups: falsethe data must be pre-sorted by group. Seedocs/llm/DESIGN.md.
gatherGroups
gatherGroups:
boolean
Defined in: base.ts:524
Whether the library gathers non-contiguous groups before rendering
(true, default). Grouping renders contiguous runs, so scattered items
sharing a key would otherwise produce a duplicate label per gap.
true: the DISPLAY order is derived via gatherItemsByGroupKey: groups in first-appearance order, within-group order kept, ungrouped (null-key) items in place. The data itself (items/getItems()) is never reordered, and already-contiguous data is detected in one scan and used as-is.false: strict mode - you guarantee the data is pre-sorted by group; a key reappearing after a gap renders a duplicate label andconsole.warns, so a broken sort is surfaced instead of silently fixed. No effect while grouping is off (every keynull).
groupKeyCompareFn
groupKeyCompareFn: ((
a,b) =>boolean) |null
Defined in: base.ts:534
Equality for two group keys; decides whether items share a group (both
the gatherGroups gather and the contiguous-run rendering use it).
null(default) = identity, the same rule as the defaultcompareFn(===, plusNaNequalsNaN); right for string / number keys.- Supply only when
GroupKeyis an object without usable reference identity. - Mirrors
compareFn, one level up.
groupKeyToStringFn
groupKeyToStringFn: ((
groupKey) =>string) |null
Defined in: base.ts:541
Group key -> the label's display text. The i18n customization point: keep keys stable, translate here.
null(default) =String(groupKey).
groupDisabledFn
groupDisabledFn: ((
groupKey) =>boolean) |null
Defined in: base.ts:549
Predicate: is this whole group disabled?
null(default) = no group disabled.true= every item in the group is treated as disabled (layers on top ofitemDisabledFn).
createGroupLabelContentElFn
createGroupLabelContentElFn: ((
groupKey,itemsInGroup) =>HTMLElement|null) |null
Defined in: base.ts:562
Group label -> its visible content ELEMENT (icon / count badge / rich
markup), without subclassing. Mirrors createItemContentElFn.
- Return an
HTMLElementand the library inserts it as the label's visible content; the group's accessible name staysgroupKeyToString(on the containeraria-label) and the label element staysaria-hidden. null(default, or returned for a group) = plain text fromgroupKeyToString.itemsInGroupis the group's items, so you can render "Fruits (4)" or a summary without recomputing the grouping.
Popup
outsideClickBehavior
outsideClickBehavior:
LLSelectOutsideClickBehavior
Defined in: base.ts:207
popupWidthPolicy
popupWidthPolicy:
LLSelectWidthPolicy
Defined in: base.ts:432
How the popup decides its width. Does NOT affect the trigger - trigger width is always whatever your CSS says.
'fit-content'(default): popup width grows to its own content (items, filter input, ...) and never shrinks below the trigger's width - the native<select>dropdown behavior, minus its viewport overflow: auto-shifts and width-clamps when the natural width would not fit. Direction-aware: in an RTL context (getComputedStyle(trigger).direction === 'rtl', read once per open) it right-aligns to the trigger and grows LEFTWARD, the mirror of LTR.'match-trigger': popup width equals trigger width; long item text wraps inside the popup.
Disabling
itemDisabledFn
itemDisabledFn: ((
item) =>boolean) |null
Defined in: base.ts:442
Predicate deciding whether an individual item is disabled. null (default)
= nothing disabled. A disabled item is not selectable (click / Enter) and is
skipped by keyboard nav; it keeps role="option" plus aria-disabled.
Re-evaluated on every render (never cached). For a generic T this is the
only way to mark items - the library cannot read a disabled field off an
unknown type. See docs/llm/DESIGN.md.
focusableWhenDisabled
focusableWhenDisabled:
boolean
Defined in: base.ts:450
When the control is disabled via setDisabled(true), whether the trigger
stays in the tab order (tabindex="0"). false (default) takes it out
(-1). Set true so keyboard / AT users can focus the disabled control to
read a "why disabled" tooltip.
i18n
uiTranslationPack
uiTranslationPack:
LLSelectUiTranslationPack
Defined in: base.ts:275
Chrome strings (AT labels + generated text): the i18n customization point. Resolved
against English: pass a language pack whole (uiTranslationPack: zhTW from
@llselect/core/i18n) or override single keys
(uiTranslationPack: { ...zhTW, filterInputPlaceholder: '...' }).
Key-by-key contract (incl. what null means where allowed):
LLSelectUiTranslationPack.
CSS
cssClassPrefix
cssClassPrefix:
string
Defined in: base.ts:135
Prefix used for every CSS class and DOM id the library generates
(default 'llselect'). NOTE: the shipped themes target the default
prefix only - a custom prefix means bringing your own CSS. Reference the
resolved names via instance.classIdMap instead of hardcoding strings.
Action rows
popupListLeadingActionRows
popupListLeadingActionRows: readonly
LLSelectPopupListActionRow[]
Defined in: base.ts:372
Commands rendered as role="option" rows at the TOP of the option list,
after the choose-all row when there is one, in array order.
- Each entry is a LLSelectPopupListActionRow. The library builds the row elements and wires them into the arrow-key ring: Home / End reach the ring's ends, disabled rows are skipped, and the popup opens with the active option on an item or the choose-all row, never on one of these rows.
- Rows scroll with the items unless their block is pinned
(
popupListLeadingRowsPinned). For content that is not a command, usecreatePopupHeaderContentElFn/createPopupFooterContentElFn. - Default
[]. The array is copied at construction; later changes to your array do nothing. - Assistive technology announces a row as an option with its text and a positional count; it has no selected state. If the command changes the selection, say so in the row text or a live region.
- A "select all" placed here is a command, not the choose-all row: call
toggleAllVisible()fromonActivateand count withgetVisibleEnabledItems()(both onLLSelectMultiple). It has no selected state and is never the active option when the popup opens. For a row with selection state, usechooseAllRow. - Contract:
docs/llm/A11Y.md"Action rows"; design:docs/llm/DESIGN.md.
popupListTrailingActionRows
popupListTrailingActionRows: readonly
LLSelectPopupListActionRow[]
Defined in: base.ts:382
Commands rendered as role="option" rows at the BOTTOM of the option
list, after the last item, in array order. Same contract as
popupListLeadingActionRows.
- While the filter is active, Home / End move the text caret, so a row down here is reached only by arrowing past every match: put commands keyboard users need often in the leading rows.
popupListLeadingRowsPinned
popupListLeadingRowsPinned:
boolean
Defined in: base.ts:405
Keep the leading rows in view while the items scroll.
- The leading rows are the choose-all row (when on) plus
popupListLeadingActionRows. Withtrue, that whole block sticks to the top edge of the listbox and the items scroll under it. - The rows stay in the arrow-key ring, keep their roles, and are still counted by assistive technology. Only their scrolling changes.
- The library wraps the block in a
divwithrole="presentation"(popupListPinnedLeadingRowsEl, classpopupListPinnedLeadingRowsClass) and setsposition: stickyandtop: 0on it inline, so the setting works in any theme. The shipped themes give the wrapper an opaque background and its edge line. - When the block has no rows, for example when the choose-all row hides because nothing is selectable and there are no leading action rows, the wrapper is not in the listbox.
- Scrolling an item into view accounts for the wrapper's height. When the pinned blocks leave no room for the items, scrolling is best-effort.
- Default
false: the rows scroll with the items. - Pinning is per block, never per row. Why:
docs/llm/popup-rows-and-callbacks.mdsection 5. Contract:docs/llm/A11Y.md"Action rows".
popupListTrailingRowsPinned
popupListTrailingRowsPinned:
boolean
Defined in: base.ts:416
Keep the trailing rows in view while the items scroll.
- The trailing rows are
popupListTrailingActionRows. Withtrue, that block sticks to the bottom edge of the listbox. - Same contract as popupListLeadingRowsPinned. The wrapper is
popupListPinnedTrailingRowsEl, classpopupListPinnedTrailingRowsClass, withbottom: 0. - Default
false.
Popup slots
createPopupHeaderContentElFn
createPopupHeaderContentElFn: ((
ctx) =>HTMLElement|null) |null
Defined in: base.ts:335
Content for a pinned header above the option list, without subclassing.
- The library calls it ONCE, inside the constructor, before
newreturns. The variable that will hold the instance is still empty: do not read it in this function. Event handlers on the returned element may read it, because they run afternewreturns. ctxis a LLSelectConstructionContext:classIdMap(for the theme's classes) anduiTranslationPack. That is all this function can safely read.- Return an
HTMLElement: the library wraps it in thepopupHeaderElcontainer (classpopupHeaderClass, no ARIA role) and keeps that node untildestroy().open(),rerender()andsetUiTranslationPack()never rebuild it. Update it yourself, fromonChangeoronOpen. null(setting default, or returned): no header element is built.- Where it sits: between the filter input and the listbox, outside the
scroll area, so it never scrolls with the items. To put it above the
filter input, move it from a subclass constructor:
if (this.popupHeaderEl) { this.popupEl.prepend(this.popupHeaderEl) }. The library never rewrites the popup's child list. A header above the filter input should hold no focusable controls, or Shift+Tab from the input lands in it instead of leaving the widget. - Pointer: a click inside keeps DOM focus on the combobox host (the popup
mousedownrule), so a button works without stealing keyboard input. A text field inside must callstopPropagationon its ownmousedown. - Keep it compact: a long unwrapped line widens a
'fit-content'popup, and a tall slot squeezes the list, the only child that flexes. - Contract:
docs/llm/DESIGN.md"Popup header / footer slots"; keyboard and focus rules:docs/llm/A11Y.md.
createPopupFooterContentElFn
createPopupFooterContentElFn: ((
ctx) =>HTMLElement|null) |null
Defined in: base.ts:347
Content for a pinned footer below the option list, without subclassing.
- Same contract as createPopupHeaderContentElFn: called once in
the constructor with a LLSelectConstructionContext, wrapped in
the
popupFooterElcontainer (classpopupFooterClass, no ARIA role), never rebuilt by the library. null(setting default, or returned): no footer element is built.- Where it sits: after the no-results message, at the bottom of the popup, outside the scroll area.
LLSelectSettingsInputOf
LLSelectSettingsInputOf<
S> =Partial<Omit<S,"uiTranslationPack">> &object
Defined in: base.ts:602
Constructor input for a resolved settings bag S: every field optional,
and uiTranslationPack accepts a PARTIAL pack (missing keys fall back to
English). Shared by the base / single / multiple *SettingsInput types;
use it for a subclass wrapper that extends the settings bag.
Type Declaration
uiTranslationPack?
optionaluiTranslationPack?:Partial<LLSelectUiTranslationPack>
Type Parameters
| Type Parameter |
|---|
S extends object |
LLSelectBaseSettingsInput
LLSelectBaseSettingsInput<
T,GroupKey> =LLSelectSettingsInputOf<LLSelectBaseSettings<T,GroupKey>>
Defined in: base.ts:612
Constructor-time settings input - every field is optional and missing fields fall back to the library defaults.
Type Parameters
| Type Parameter | Default type |
|---|---|
T |
- |
GroupKey |
string |
Single
LLSelectSingleTriggerContext
Defined in: single.ts:14
Context passed to LLSelectSingleSettings.createTriggerContentElFn.
Type Parameters
| Type Parameter |
|---|
T |
Properties
chosenItem
chosenItem:
T|undefined
Defined in: single.ts:15
items
items: readonly
T[]
Defined in: single.ts:16
LLSelectSingleSettings
Defined in: single.ts:26
Resolved (defaults applied) settings for LLSelectSingle: the base
settings plus the single-mode fields - the runtime type of this.settings,
one bag built complete in the constructor.
Extends
LLSelectBaseSettings<T,GroupKey>
Type Parameters
| Type Parameter | Default type |
|---|---|
T |
- |
GroupKey |
string |
Items
compareFn
compareFn: (
a,b) =>boolean
Defined in: base.ts:202
Equality predicate for item values - return true when a and b are the
same item.
- Required for non-primitive
T. The default compares by identity:===, except thatNaNequalsNaN(SameValueZero, the same ruleSetuses), so every code path agrees on what "the same item" means. - Used for selection, dedup, and matching the chosen item back to the list.
- Symmetric: do not depend on which argument is the candidate vs the existing item.
Parameters
| Parameter | Type |
|---|---|
a |
T |
b |
T |
Returns
boolean
Inherited from
itemToStringFn
itemToStringFn: ((
item) =>string) |null
Defined in: base.ts:460
Item -> display string, without subclassing.
null(default) =String(item).- Read by the
itemToStringmethod's default; used for list text, the single trigger text, the option's accessible name, and the default filter. Inserted astextContent(plain text, NOT parsed as HTML). - For rich content (icons etc.), pass
createItemContentElFn.
Inherited from
createItemContentElFn
createItemContentElFn: ((
item) =>HTMLElement|null) |null
Defined in: base.ts:496
Item -> the visible content ELEMENT of its list row, without subclassing.
- Return an
HTMLElementand the library inserts it as-is (you own the node); it becomes the row's visible content. null= plaintextContentfromitemToString. This is the default, both when the setting is unset and when your function returnsnullfor a particular item.- Fills the VISIBLE content only. You never touch
aria-*: when this returns an element the library sets the option'saria-labelfromitemToString, so the accessible name + match text stay owned byitemToStringno matter what you render (icon-only, reordered, ...). To make the spoken/matched text differ from the visible content, set the two independently:itemToStringFnfor the name/matching,createItemContentElFnfor the look. - For full control of the option element (tag / wiring), subclass
createItemElinstead. - Runs per rendered row per render, and re-runs whenever a row is
rebuilt: open, filter,
setItems, AND chosen-state changes (both modes replace the affected rows in place while the popup is open). Content that reads selection state (e.g. a checkmark on the chosen row viacreateCheckmarkSvgEl) therefore stays fresh; keep the function cheap.
Example
// List shows an icon + the item text; screen readers announce just that text.
itemToStringFn: (lang) => lang.name,
createItemContentElFn: (lang) => {
const row = document.createElement('span')
const icon = document.createElement('i')
icon.className = `mdi mdi-${lang.icon}`
icon.setAttribute('aria-hidden', 'true') // decorative
row.append(icon, lang.name)
return row
}
Inherited from
Accessible name
ariaLabel
ariaLabel:
string|null
Defined in: base.ts:161
Accessible name of the field, like the <label> text of a native
<select> (e.g. 'Country').
- Applied to the trigger, the popup listbox, and (while the filter is active)
the filter input; per-mode wiring:
docs/llm/A11Y.md"Accessible name". - The name resolves by the FIRST set rung, mirroring the W3C
accessible-name computation order:
ariaLabelledBy.ariaLabel(this setting).labelEl- its element's id becomes the resolvedariaLabelledBy.- None set: the field is unnamed. A combobox requires a name
(WAI-ARIA 1.2), so one
console.warnper page reports the first offender.
null(default): this rung is skipped. An empty or whitespace-only string counts as unset too - the accname computation skips a blankaria-label, and so does the ladder.
Inherited from
ariaLabelledBy
ariaLabelledBy:
string|null
Defined in: base.ts:174
Space-separated DOM id(s) of the visible label element(s) naming the
field; forwarded as aria-labelledby to the same elements as ariaLabel.
- Prefer this over
ariaLabelwhen a visible label element exists: the spoken name then always matches the visible text. null(default): not forwarded; seeariaLabelfor the naming requirement. An empty or whitespace-only string counts as unset too, same asariaLabel.- Rung 1 of the resolution order (the numbered list at
ariaLabel): it wins whenever set, matching the ARIA name computation.
Inherited from
labelEl
labelEl:
HTMLElement|null
Defined in: base.ts:190
The widget's visible label element - the one foreign element the library
touches. Emulates native <label for> (which cannot target these divs)
in both directions:
- clicking it focuses the trigger (focus ONLY; native
<select>does not open on label click, neither does this); - it feeds the accessible name as rung 3 of the resolution order (the
numbered list at
ariaLabel): with neither aria setting given, the label's id becomes the resolvedariaLabelledBy(an id is minted fromclassIdMap.labelIdif the element has none) - a live reference, so later label text changes stay correct. null= no label element; the name ladder just skips this rung.destroy()removes the click listener and a minted id.
Inherited from
Events
onOpen
onOpen: (() =>
void) |null
Defined in: base.ts:571
Fired right after the popup opens. An open() call that does not actually
open the popup (already open, a disabled control, or a trigger scrolled out
of view or clipped) does not fire it. Fires in ADDITION to the protected
onOpened hook - the setting is for consumers, the hook for subclasses;
both run. null (default) = nothing.
Inherited from
onClose
onClose: (() =>
void) |null
Defined in: base.ts:577
Fired right after the popup closes. A no-op close() does not fire it.
Additive with the protected onClosed hook, like onOpen.
Inherited from
onFilterQueryChange
onFilterQueryChange: ((
query) =>void) |null
Defined in: base.ts:591
Called after the filter text changed and the list was re-rendered.
- Fires on typing, when an IME composition ends, and when Esc clears a
non-empty query.
queryis the new text. - Does not fire when the text stays the same, when
close()clears the query (useonClose), whenopen()starts with an empty query, or onsetItems()/rerender(). - Runs after the list is rebuilt, so
getVisibleItems()already reflects the new text. Rewrite a header count from here, fromonOpenand fromonChange. null(default): nothing is called.
Inherited from
onChange
onChange: ((
chosenItem,previousChosenItem,meta) =>void) |null
Defined in: single.ts:38
Fired when the chosen item actually changes (compared via compareFn).
Receives the new value and the PREVIOUS one (the snapshot from before
this change); undefined means "no selection" on either side. Does NOT
fire on construction nor on setChosenItem with an equivalent item.
null (default) = no listener.
meta.sourcesays who initiated the change:'user'for a pointer or keyboard interaction inside the widget,'api'for any programmatic call. See LLSelectChangeMeta.
Trigger
placeholder
placeholder:
string
Defined in: base.ts:142
Text shown in the trigger when nothing is selected. App copy: an explicit
value always wins; when unset, the locale default
uiTranslationPack.triggerPlaceholder is used ('Please select' in English).
Inherited from
createTriggerArrowContentElFn
createTriggerArrowContentElFn: ((
state) =>HTMLElement|SVGElement|null) |null
Defined in: base.ts:216
The trigger arrow slot's content ELEMENT (typically a dropdown chevron or
triangle). Called whenever the arrow may need to change - including on
every open/close - so the returned element can vary with isOpened.
- fn returns
null- no arrow for that state. - setting is
null(default) - the library adds nothing to the arrow slot.
Inherited from
clearable
clearable:
boolean
Defined in: base.ts:241
Whether the trigger shows a clear (x) button that empties the selection.
- Default
false. - Clearing sets the empty value:
undefinedfor a single select,[]for a multiple. It goes through the normal setters, soonChangefires with that empty value. There is no separate clear event. - The empty value is not configurable, and no library makes it so:
"nothing chosen" already exists before the first choice, so the value
types carry
undefinedeither way. - If your model is a plain type like
stringand must never holdundefined, pick one of these:- Add a real "none" item (for example
''shown as "(none)") and skipclearable. The model then staysstringafter the first choice, exactly like a native<select>with a placeholder option. - Keep
clearableand coerce inonChange:item ?? ''.
- Add a real "none" item (for example
- "Clear" means back to empty and the placeholder, never "back to some
default option". If you want a default instead, set it yourself in
onChange. - The button sits in its OWN trigger slot (like the arrow, so it never
collides with
createTriggerContentElFn), istabindex="-1", and carries anaria-label. The theme hides it viadata-emptywhile nothing is selected.
Inherited from
createTriggerClearButtonContentElFn
createTriggerClearButtonContentElFn: (() =>
HTMLElement|SVGElement|null) |null
Defined in: base.ts:248
Content ELEMENT of the clear button (its x icon), mirroring createTriggerArrowContentElFn.
null (default) = the theme's CSS glyph. The library always owns the button,
its click (clears + stops propagation) and aria; this only fills the icon.
Inherited from
createTriggerContentElFn
createTriggerContentElFn: ((
ctx) =>HTMLElement|null) |null
Defined in: single.ts:53
Render the trigger's content ELEMENT without subclassing - the setting
equivalent of overriding renderTriggerContent. Receives the chosen item
- items (same convention as
createItemContentElFn):
HTMLElement- inserted into the trigger as-is; you own it. Use this for real markup (icon + text, etc.).- fn returns
null- use the default for this render: the chosen item'sitemToString, or the placeholder when nothing is chosen. - setting is
null(default) - always use that default rendering. The DEFAULTrenderTriggerContentchecks it first; a subclass override replaces that default entirely and may ignore the setting - override wins, per DESIGN.md "Customization model".
Filtering
filterable
filterable:
boolean| ((items) =>boolean)
Defined in: base.ts:265
Whether the popup includes a filter input.
false(default): never.true: always.- Predicate
(items) => boolean: conditional - evaluated against the CURRENT full item list each time the popup OPENS (never mid-open; asetItemscrossing the threshold applies on the next open). E.g.filterable: (items) => items.length > 10. A printable key pressed while CLOSED also calls the predicate, read-only, to decide whether prefix typeahead may take the key - keep it cheap and side-effect free. The ARIA mode follows the evaluated value per open cycle: active = triggerrole="button", focus moves to the input; inactive = exactly likefilterable: false(trigger staysrole="combobox", focus stays on the trigger). Seedocs/llm/A11Y.mdanddocs/llm/DESIGN.md.
Inherited from
filterFn
filterFn: ((
item,query) =>boolean) |null
Defined in: base.ts:287
Predicate used by the filter input; return true to keep the item.
null (default) means the built-in case-insensitive substring match
against the item's resolved text (itemToStringFn / itemToString).
Pass a custom function for fuzzy / domain-specific matching.
queryis the RAW input value: not trimmed and not lower-cased. Normalize it yourself (the built-in lower-cases both sides; it does not trim).- Not called while the query is empty (an empty box shows every item), but a
whitespace-only query (e.g.
" ") does call it.
Inherited from
createPopupListNoResultsContentElFn
createPopupListNoResultsContentElFn: ((
query) =>HTMLElement|null) |null
Defined in: base.ts:304
The no-results message's visible content ELEMENT, without subclassing.
Mirrors createItemContentElFn: the library owns the message container
(role="status", class, show/hide), this fills its content only.
queryis the current filter query (''when the filter is inactive or the list is simply empty), so "Nothing matches" is possible. - Return an
HTMLElement: inserted as the content (you own it; include real text - the status region announces its TEXT content). null(setting default, or returned): plain text fromuiTranslationPack.popupListNoResults. Re-evaluated every time the message is shown (the query may differ). The DOM is refreshed only when the resolved TEXT changes - the status region is keyed on text so it announces once, not per keystroke - so rich content whose visible markup varies while its text stays constant is not re-rendered.
Inherited from
Grouping
itemToGroupKeyFn
itemToGroupKeyFn: ((
item) =>GroupKey|null) |null
Defined in: base.ts:507
Item -> its group's key (identity), enabling optgroup rendering.
null(setting, default): grouping off - flat list, no labels.- fn returns
null: this item is in no group; renders ungrouped. - Contiguous items with an equal key (per
groupKeyCompareFn) form one group. By default non-contiguous data is first gathered into display order (gatherGroups); withgatherGroups: falsethe data must be pre-sorted by group. Seedocs/llm/DESIGN.md.
Inherited from
gatherGroups
gatherGroups:
boolean
Defined in: base.ts:524
Whether the library gathers non-contiguous groups before rendering
(true, default). Grouping renders contiguous runs, so scattered items
sharing a key would otherwise produce a duplicate label per gap.
true: the DISPLAY order is derived via gatherItemsByGroupKey: groups in first-appearance order, within-group order kept, ungrouped (null-key) items in place. The data itself (items/getItems()) is never reordered, and already-contiguous data is detected in one scan and used as-is.false: strict mode - you guarantee the data is pre-sorted by group; a key reappearing after a gap renders a duplicate label andconsole.warns, so a broken sort is surfaced instead of silently fixed. No effect while grouping is off (every keynull).
Inherited from
groupKeyCompareFn
groupKeyCompareFn: ((
a,b) =>boolean) |null
Defined in: base.ts:534
Equality for two group keys; decides whether items share a group (both
the gatherGroups gather and the contiguous-run rendering use it).
null(default) = identity, the same rule as the defaultcompareFn(===, plusNaNequalsNaN); right for string / number keys.- Supply only when
GroupKeyis an object without usable reference identity. - Mirrors
compareFn, one level up.
Inherited from
groupKeyToStringFn
groupKeyToStringFn: ((
groupKey) =>string) |null
Defined in: base.ts:541
Group key -> the label's display text. The i18n customization point: keep keys stable, translate here.
null(default) =String(groupKey).
Inherited from
groupDisabledFn
groupDisabledFn: ((
groupKey) =>boolean) |null
Defined in: base.ts:549
Predicate: is this whole group disabled?
null(default) = no group disabled.true= every item in the group is treated as disabled (layers on top ofitemDisabledFn).
Inherited from
createGroupLabelContentElFn
createGroupLabelContentElFn: ((
groupKey,itemsInGroup) =>HTMLElement|null) |null
Defined in: base.ts:562
Group label -> its visible content ELEMENT (icon / count badge / rich
markup), without subclassing. Mirrors createItemContentElFn.
- Return an
HTMLElementand the library inserts it as the label's visible content; the group's accessible name staysgroupKeyToString(on the containeraria-label) and the label element staysaria-hidden. null(default, or returned for a group) = plain text fromgroupKeyToString.itemsInGroupis the group's items, so you can render "Fruits (4)" or a summary without recomputing the grouping.
Inherited from
Popup
outsideClickBehavior
outsideClickBehavior:
LLSelectOutsideClickBehavior
Defined in: base.ts:207
See LLSelectOutsideClickBehavior.
Inherited from
popupWidthPolicy
popupWidthPolicy:
LLSelectWidthPolicy
Defined in: base.ts:432
How the popup decides its width. Does NOT affect the trigger - trigger width is always whatever your CSS says.
'fit-content'(default): popup width grows to its own content (items, filter input, ...) and never shrinks below the trigger's width - the native<select>dropdown behavior, minus its viewport overflow: auto-shifts and width-clamps when the natural width would not fit. Direction-aware: in an RTL context (getComputedStyle(trigger).direction === 'rtl', read once per open) it right-aligns to the trigger and grows LEFTWARD, the mirror of LTR.'match-trigger': popup width equals trigger width; long item text wraps inside the popup.
Inherited from
Disabling
itemDisabledFn
itemDisabledFn: ((
item) =>boolean) |null
Defined in: base.ts:442
Predicate deciding whether an individual item is disabled. null (default)
= nothing disabled. A disabled item is not selectable (click / Enter) and is
skipped by keyboard nav; it keeps role="option" plus aria-disabled.
Re-evaluated on every render (never cached). For a generic T this is the
only way to mark items - the library cannot read a disabled field off an
unknown type. See docs/llm/DESIGN.md.
Inherited from
focusableWhenDisabled
focusableWhenDisabled:
boolean
Defined in: base.ts:450
When the control is disabled via setDisabled(true), whether the trigger
stays in the tab order (tabindex="0"). false (default) takes it out
(-1). Set true so keyboard / AT users can focus the disabled control to
read a "why disabled" tooltip.
Inherited from
i18n
uiTranslationPack
uiTranslationPack:
LLSelectUiTranslationPack
Defined in: base.ts:275
Chrome strings (AT labels + generated text): the i18n customization point. Resolved
against English: pass a language pack whole (uiTranslationPack: zhTW from
@llselect/core/i18n) or override single keys
(uiTranslationPack: { ...zhTW, filterInputPlaceholder: '...' }).
Key-by-key contract (incl. what null means where allowed):
LLSelectUiTranslationPack.
Inherited from
CSS
cssClassPrefix
cssClassPrefix:
string
Defined in: base.ts:135
Prefix used for every CSS class and DOM id the library generates
(default 'llselect'). NOTE: the shipped themes target the default
prefix only - a custom prefix means bringing your own CSS. Reference the
resolved names via instance.classIdMap instead of hardcoding strings.
Inherited from
Action rows
popupListLeadingActionRows
popupListLeadingActionRows: readonly
LLSelectPopupListActionRow[]
Defined in: base.ts:372
Commands rendered as role="option" rows at the TOP of the option list,
after the choose-all row when there is one, in array order.
- Each entry is a LLSelectPopupListActionRow. The library builds the row elements and wires them into the arrow-key ring: Home / End reach the ring's ends, disabled rows are skipped, and the popup opens with the active option on an item or the choose-all row, never on one of these rows.
- Rows scroll with the items unless their block is pinned
(
popupListLeadingRowsPinned). For content that is not a command, usecreatePopupHeaderContentElFn/createPopupFooterContentElFn. - Default
[]. The array is copied at construction; later changes to your array do nothing. - Assistive technology announces a row as an option with its text and a positional count; it has no selected state. If the command changes the selection, say so in the row text or a live region.
- A "select all" placed here is a command, not the choose-all row: call
toggleAllVisible()fromonActivateand count withgetVisibleEnabledItems()(both onLLSelectMultiple). It has no selected state and is never the active option when the popup opens. For a row with selection state, usechooseAllRow. - Contract:
docs/llm/A11Y.md"Action rows"; design:docs/llm/DESIGN.md.
Inherited from
popupListTrailingActionRows
popupListTrailingActionRows: readonly
LLSelectPopupListActionRow[]
Defined in: base.ts:382
Commands rendered as role="option" rows at the BOTTOM of the option
list, after the last item, in array order. Same contract as
popupListLeadingActionRows.
- While the filter is active, Home / End move the text caret, so a row down here is reached only by arrowing past every match: put commands keyboard users need often in the leading rows.
Inherited from
popupListLeadingRowsPinned
popupListLeadingRowsPinned:
boolean
Defined in: base.ts:405
Keep the leading rows in view while the items scroll.
- The leading rows are the choose-all row (when on) plus
popupListLeadingActionRows. Withtrue, that whole block sticks to the top edge of the listbox and the items scroll under it. - The rows stay in the arrow-key ring, keep their roles, and are still counted by assistive technology. Only their scrolling changes.
- The library wraps the block in a
divwithrole="presentation"(popupListPinnedLeadingRowsEl, classpopupListPinnedLeadingRowsClass) and setsposition: stickyandtop: 0on it inline, so the setting works in any theme. The shipped themes give the wrapper an opaque background and its edge line. - When the block has no rows, for example when the choose-all row hides because nothing is selectable and there are no leading action rows, the wrapper is not in the listbox.
- Scrolling an item into view accounts for the wrapper's height. When the pinned blocks leave no room for the items, scrolling is best-effort.
- Default
false: the rows scroll with the items. - Pinning is per block, never per row. Why:
docs/llm/popup-rows-and-callbacks.mdsection 5. Contract:docs/llm/A11Y.md"Action rows".
Inherited from
popupListTrailingRowsPinned
popupListTrailingRowsPinned:
boolean
Defined in: base.ts:416
Keep the trailing rows in view while the items scroll.
- The trailing rows are
popupListTrailingActionRows. Withtrue, that block sticks to the bottom edge of the listbox. - Same contract as popupListLeadingRowsPinned. The wrapper is
popupListPinnedTrailingRowsEl, classpopupListPinnedTrailingRowsClass, withbottom: 0. - Default
false.
Inherited from
Popup slots
createPopupHeaderContentElFn
createPopupHeaderContentElFn: ((
ctx) =>HTMLElement|null) |null
Defined in: base.ts:335
Content for a pinned header above the option list, without subclassing.
- The library calls it ONCE, inside the constructor, before
newreturns. The variable that will hold the instance is still empty: do not read it in this function. Event handlers on the returned element may read it, because they run afternewreturns. ctxis a LLSelectConstructionContext:classIdMap(for the theme's classes) anduiTranslationPack. That is all this function can safely read.- Return an
HTMLElement: the library wraps it in thepopupHeaderElcontainer (classpopupHeaderClass, no ARIA role) and keeps that node untildestroy().open(),rerender()andsetUiTranslationPack()never rebuild it. Update it yourself, fromonChangeoronOpen. null(setting default, or returned): no header element is built.- Where it sits: between the filter input and the listbox, outside the
scroll area, so it never scrolls with the items. To put it above the
filter input, move it from a subclass constructor:
if (this.popupHeaderEl) { this.popupEl.prepend(this.popupHeaderEl) }. The library never rewrites the popup's child list. A header above the filter input should hold no focusable controls, or Shift+Tab from the input lands in it instead of leaving the widget. - Pointer: a click inside keeps DOM focus on the combobox host (the popup
mousedownrule), so a button works without stealing keyboard input. A text field inside must callstopPropagationon its ownmousedown. - Keep it compact: a long unwrapped line widens a
'fit-content'popup, and a tall slot squeezes the list, the only child that flexes. - Contract:
docs/llm/DESIGN.md"Popup header / footer slots"; keyboard and focus rules:docs/llm/A11Y.md.
Inherited from
createPopupFooterContentElFn
createPopupFooterContentElFn: ((
ctx) =>HTMLElement|null) |null
Defined in: base.ts:347
Content for a pinned footer below the option list, without subclassing.
- Same contract as createPopupHeaderContentElFn: called once in
the constructor with a LLSelectConstructionContext, wrapped in
the
popupFooterElcontainer (classpopupFooterClass, no ARIA role), never rebuilt by the library. null(setting default, or returned): no footer element is built.- Where it sits: after the no-results message, at the bottom of the popup, outside the scroll area.
Inherited from
LLSelectBaseSettings.createPopupFooterContentElFn
LLSelectSingleSettingsInput
LLSelectSingleSettingsInput<
T,GroupKey> =LLSelectSettingsInputOf<LLSelectSingleSettings<T,GroupKey>>
Defined in: single.ts:62
Constructor-time settings input for LLSelectSingle. Every field is optional; missing fields use defaults.
Type Parameters
| Type Parameter | Default type |
|---|---|
T |
- |
GroupKey |
string |
Multiple
LLSelectTriggerDisplay
LLSelectTriggerDisplay =
"count"|"tags"
Defined in: multiple.ts:17
Trigger display mode of LLSelectMultiple.
'count': a text summary like "3 / 10 selected".'tags': one removable chip per chosen item. See LLSelectMultipleSettings.triggerDisplay.
LLSelectChosenState
LLSelectChosenState =
"none"|"some"|"all"
Defined in: multiple.ts:25
Tri-state of the choose-all row (also the data-chosen-state attribute
value): how much of the VISIBLE enabled subset is currently chosen.
LLSelectMultipleTriggerContext
Defined in: multiple.ts:32
Context passed to LLSelectMultipleSettings.createTriggerContentElFn.
Type Parameters
| Type Parameter |
|---|
T |
Properties
chosenItems
chosenItems: readonly
T[]
Defined in: multiple.ts:33
items
items: readonly
T[]
Defined in: multiple.ts:34
LLSelectMultipleSettings
Defined in: multiple.ts:44
Resolved (defaults applied) settings for LLSelectMultiple: the base
settings plus the multi-mode fields - the runtime type of this.settings,
one bag built complete in the constructor.
Extends
LLSelectBaseSettings<T,GroupKey>
Type Parameters
| Type Parameter | Default type |
|---|---|
T |
- |
GroupKey |
string |
Items
compareFn
compareFn: (
a,b) =>boolean
Defined in: base.ts:202
Equality predicate for item values - return true when a and b are the
same item.
- Required for non-primitive
T. The default compares by identity:===, except thatNaNequalsNaN(SameValueZero, the same ruleSetuses), so every code path agrees on what "the same item" means. - Used for selection, dedup, and matching the chosen item back to the list.
- Symmetric: do not depend on which argument is the candidate vs the existing item.
Parameters
| Parameter | Type |
|---|---|
a |
T |
b |
T |
Returns
boolean
Inherited from
itemToStringFn
itemToStringFn: ((
item) =>string) |null
Defined in: base.ts:460
Item -> display string, without subclassing.
null(default) =String(item).- Read by the
itemToStringmethod's default; used for list text, the single trigger text, the option's accessible name, and the default filter. Inserted astextContent(plain text, NOT parsed as HTML). - For rich content (icons etc.), pass
createItemContentElFn.
Inherited from
createItemContentElFn
createItemContentElFn: ((
item) =>HTMLElement|null) |null
Defined in: base.ts:496
Item -> the visible content ELEMENT of its list row, without subclassing.
- Return an
HTMLElementand the library inserts it as-is (you own the node); it becomes the row's visible content. null= plaintextContentfromitemToString. This is the default, both when the setting is unset and when your function returnsnullfor a particular item.- Fills the VISIBLE content only. You never touch
aria-*: when this returns an element the library sets the option'saria-labelfromitemToString, so the accessible name + match text stay owned byitemToStringno matter what you render (icon-only, reordered, ...). To make the spoken/matched text differ from the visible content, set the two independently:itemToStringFnfor the name/matching,createItemContentElFnfor the look. - For full control of the option element (tag / wiring), subclass
createItemElinstead. - Runs per rendered row per render, and re-runs whenever a row is
rebuilt: open, filter,
setItems, AND chosen-state changes (both modes replace the affected rows in place while the popup is open). Content that reads selection state (e.g. a checkmark on the chosen row viacreateCheckmarkSvgEl) therefore stays fresh; keep the function cheap.
Example
// List shows an icon + the item text; screen readers announce just that text.
itemToStringFn: (lang) => lang.name,
createItemContentElFn: (lang) => {
const row = document.createElement('span')
const icon = document.createElement('i')
icon.className = `mdi mdi-${lang.icon}`
icon.setAttribute('aria-hidden', 'true') // decorative
row.append(icon, lang.name)
return row
}
Inherited from
hideChosenRows
hideChosenRows:
boolean
Defined in: multiple.ts:126
Hide the rows of chosen items from the popup list.
- Default
false: chosen rows stay listed and show their state. - While
true, choosing an item removes its row at once and unchoosing puts it back. Tags, the trigger andgetChosenItemsare unaffected. - When every item is chosen, the popup shows the no-results element.
- With
chooseAllRow, the visible subset is always fully unchosen, so the row acts as "choose everything still listed", its tri-state never reaches all-chosen, and it disappears with the last actionable row. - Internals: a
getVisibleItemssubtraction. The defaultcompareFnuses a Set lookup; a customcompareFncosts O(visible x chosen). Either cost is paid once per change of the list or the chosen set - the result is cached between changes.toggleItemswaps its O(1) row replace for a full rebuild.
Accessible name
ariaLabel
ariaLabel:
string|null
Defined in: base.ts:161
Accessible name of the field, like the <label> text of a native
<select> (e.g. 'Country').
- Applied to the trigger, the popup listbox, and (while the filter is active)
the filter input; per-mode wiring:
docs/llm/A11Y.md"Accessible name". - The name resolves by the FIRST set rung, mirroring the W3C
accessible-name computation order:
ariaLabelledBy.ariaLabel(this setting).labelEl- its element's id becomes the resolvedariaLabelledBy.- None set: the field is unnamed. A combobox requires a name
(WAI-ARIA 1.2), so one
console.warnper page reports the first offender.
null(default): this rung is skipped. An empty or whitespace-only string counts as unset too - the accname computation skips a blankaria-label, and so does the ladder.
Inherited from
ariaLabelledBy
ariaLabelledBy:
string|null
Defined in: base.ts:174
Space-separated DOM id(s) of the visible label element(s) naming the
field; forwarded as aria-labelledby to the same elements as ariaLabel.
- Prefer this over
ariaLabelwhen a visible label element exists: the spoken name then always matches the visible text. null(default): not forwarded; seeariaLabelfor the naming requirement. An empty or whitespace-only string counts as unset too, same asariaLabel.- Rung 1 of the resolution order (the numbered list at
ariaLabel): it wins whenever set, matching the ARIA name computation.
Inherited from
labelEl
labelEl:
HTMLElement|null
Defined in: base.ts:190
The widget's visible label element - the one foreign element the library
touches. Emulates native <label for> (which cannot target these divs)
in both directions:
- clicking it focuses the trigger (focus ONLY; native
<select>does not open on label click, neither does this); - it feeds the accessible name as rung 3 of the resolution order (the
numbered list at
ariaLabel): with neither aria setting given, the label's id becomes the resolvedariaLabelledBy(an id is minted fromclassIdMap.labelIdif the element has none) - a live reference, so later label text changes stay correct. null= no label element; the name ladder just skips this rung.destroy()removes the click listener and a minted id.
Inherited from
Events
onOpen
onOpen: (() =>
void) |null
Defined in: base.ts:571
Fired right after the popup opens. An open() call that does not actually
open the popup (already open, a disabled control, or a trigger scrolled out
of view or clipped) does not fire it. Fires in ADDITION to the protected
onOpened hook - the setting is for consumers, the hook for subclasses;
both run. null (default) = nothing.
Inherited from
onClose
onClose: (() =>
void) |null
Defined in: base.ts:577
Fired right after the popup closes. A no-op close() does not fire it.
Additive with the protected onClosed hook, like onOpen.
Inherited from
onFilterQueryChange
onFilterQueryChange: ((
query) =>void) |null
Defined in: base.ts:591
Called after the filter text changed and the list was re-rendered.
- Fires on typing, when an IME composition ends, and when Esc clears a
non-empty query.
queryis the new text. - Does not fire when the text stays the same, when
close()clears the query (useonClose), whenopen()starts with an empty query, or onsetItems()/rerender(). - Runs after the list is rebuilt, so
getVisibleItems()already reflects the new text. Rewrite a header count from here, fromonOpenand fromonChange. null(default): nothing is called.
Inherited from
onChange
onChange: ((
chosenItems,previousChosenItems,meta) =>void) |null
Defined in: multiple.ts:58
Fired when the chosen-items set actually changes. Receives the new set
and the PREVIOUS one (the snapshot from before this change) - diff them
with compareFn to compute added / removed. Does NOT fire on
construction nor on a setter call that yields an equivalent set
(element-wise compared via compareFn, order-sensitive).
null (default) = no listener.
meta.sourcesays who initiated the change:'user'for a pointer or keyboard interaction inside the widget (an option toggle, a tag's remove button, the clear button, the choose-all row),'api'for any programmatic call. See LLSelectChangeMeta.
Trigger
placeholder
placeholder:
string
Defined in: base.ts:142
Text shown in the trigger when nothing is selected. App copy: an explicit
value always wins; when unset, the locale default
uiTranslationPack.triggerPlaceholder is used ('Please select' in English).
Inherited from
createTriggerArrowContentElFn
createTriggerArrowContentElFn: ((
state) =>HTMLElement|SVGElement|null) |null
Defined in: base.ts:216
The trigger arrow slot's content ELEMENT (typically a dropdown chevron or
triangle). Called whenever the arrow may need to change - including on
every open/close - so the returned element can vary with isOpened.
- fn returns
null- no arrow for that state. - setting is
null(default) - the library adds nothing to the arrow slot.
Inherited from
clearable
clearable:
boolean
Defined in: base.ts:241
Whether the trigger shows a clear (x) button that empties the selection.
- Default
false. - Clearing sets the empty value:
undefinedfor a single select,[]for a multiple. It goes through the normal setters, soonChangefires with that empty value. There is no separate clear event. - The empty value is not configurable, and no library makes it so:
"nothing chosen" already exists before the first choice, so the value
types carry
undefinedeither way. - If your model is a plain type like
stringand must never holdundefined, pick one of these:- Add a real "none" item (for example
''shown as "(none)") and skipclearable. The model then staysstringafter the first choice, exactly like a native<select>with a placeholder option. - Keep
clearableand coerce inonChange:item ?? ''.
- Add a real "none" item (for example
- "Clear" means back to empty and the placeholder, never "back to some
default option". If you want a default instead, set it yourself in
onChange. - The button sits in its OWN trigger slot (like the arrow, so it never
collides with
createTriggerContentElFn), istabindex="-1", and carries anaria-label. The theme hides it viadata-emptywhile nothing is selected.
Inherited from
createTriggerClearButtonContentElFn
createTriggerClearButtonContentElFn: (() =>
HTMLElement|SVGElement|null) |null
Defined in: base.ts:248
Content ELEMENT of the clear button (its x icon), mirroring createTriggerArrowContentElFn.
null (default) = the theme's CSS glyph. The library always owns the button,
its click (clears + stops propagation) and aria; this only fills the icon.
Inherited from
createTriggerContentElFn
createTriggerContentElFn: ((
ctx) =>HTMLElement|null) |null
Defined in: multiple.ts:72
Render the trigger's content ELEMENT without subclassing - the setting
equivalent of overriding renderTriggerContent. Receives the chosen items
- items (same convention as
createItemContentElFn):
HTMLElement- inserted into the trigger as-is; you own it. Use this for real markup such as tag chips.- fn returns
null- use the default for this render (count summary / tags). - setting is
null(default) - always use that default rendering. The DEFAULTrenderTriggerContentchecks it first; a subclass override replaces that default entirely and may ignore the setting - override wins, per DESIGN.md "Customization model".
triggerDisplay
triggerDisplay:
LLSelectTriggerDisplay
Defined in: multiple.ts:80
Trigger display mode.
'count'(default): a summary like "3 / 10 selected".'tags': one removable chip per chosen item; its x button removes it.createTriggerContentElFnoverrides both (full control wins).
createTagContentElFn
createTagContentElFn: ((
item) =>HTMLElement|null) |null
Defined in: multiple.ts:97
Item -> the visible content ELEMENT of its tag chip in 'tags' mode,
without subclassing. Mirrors createItemContentElFn (the chip is to the
trigger what the option content is to the row):
- Return an
HTMLElementand the library inserts it as the chip's content; the library still owns the chip container + the remove (x) button + aria. null(setting default, or returned for an item) = plain text fromitemToString.- The remove button's accessible name comes from
itemToTagRemoveButtonAriaLabel(defaultRemove <itemToString>) - that is what AT is guaranteed to announce. The chip is a generic<span>(ARIA prohibits naming it), so for icon-only content include your own (visually hidden) text if the chip should be announced as more than its remove button. Seedocs/llm/A11Y.md"Tags".
createTagRemoveButtonContentElFn
createTagRemoveButtonContentElFn: ((
item) =>HTMLElement|SVGElement|null) |null
Defined in: multiple.ts:109
Icon ELEMENT of each tag's remove (x) button in 'tags' mode, mirroring
createTriggerClearButtonContentElFn (the clear button's icon hook). The library always owns the
button, its click (removes the item + stopPropagation), tabindex="-1", and
the aria-label accessible name (from itemToTagRemoveButtonAriaLabel);
this only fills the decorative icon.
- Return an
HTMLElement/SVGElement: appended inside the button as its icon. null(setting default, or returned for an item): no icon - the theme draws the x via its CSS glyph (.llselect-tag-remove-button:empty::before).
Filtering
filterable
filterable:
boolean| ((items) =>boolean)
Defined in: base.ts:265
Whether the popup includes a filter input.
false(default): never.true: always.- Predicate
(items) => boolean: conditional - evaluated against the CURRENT full item list each time the popup OPENS (never mid-open; asetItemscrossing the threshold applies on the next open). E.g.filterable: (items) => items.length > 10. A printable key pressed while CLOSED also calls the predicate, read-only, to decide whether prefix typeahead may take the key - keep it cheap and side-effect free. The ARIA mode follows the evaluated value per open cycle: active = triggerrole="button", focus moves to the input; inactive = exactly likefilterable: false(trigger staysrole="combobox", focus stays on the trigger). Seedocs/llm/A11Y.mdanddocs/llm/DESIGN.md.
Inherited from
filterFn
filterFn: ((
item,query) =>boolean) |null
Defined in: base.ts:287
Predicate used by the filter input; return true to keep the item.
null (default) means the built-in case-insensitive substring match
against the item's resolved text (itemToStringFn / itemToString).
Pass a custom function for fuzzy / domain-specific matching.
queryis the RAW input value: not trimmed and not lower-cased. Normalize it yourself (the built-in lower-cases both sides; it does not trim).- Not called while the query is empty (an empty box shows every item), but a
whitespace-only query (e.g.
" ") does call it.
Inherited from
createPopupListNoResultsContentElFn
createPopupListNoResultsContentElFn: ((
query) =>HTMLElement|null) |null
Defined in: base.ts:304
The no-results message's visible content ELEMENT, without subclassing.
Mirrors createItemContentElFn: the library owns the message container
(role="status", class, show/hide), this fills its content only.
queryis the current filter query (''when the filter is inactive or the list is simply empty), so "Nothing matches" is possible. - Return an
HTMLElement: inserted as the content (you own it; include real text - the status region announces its TEXT content). null(setting default, or returned): plain text fromuiTranslationPack.popupListNoResults. Re-evaluated every time the message is shown (the query may differ). The DOM is refreshed only when the resolved TEXT changes - the status region is keyed on text so it announces once, not per keystroke - so rich content whose visible markup varies while its text stays constant is not re-rendered.
Inherited from
Grouping
itemToGroupKeyFn
itemToGroupKeyFn: ((
item) =>GroupKey|null) |null
Defined in: base.ts:507
Item -> its group's key (identity), enabling optgroup rendering.
null(setting, default): grouping off - flat list, no labels.- fn returns
null: this item is in no group; renders ungrouped. - Contiguous items with an equal key (per
groupKeyCompareFn) form one group. By default non-contiguous data is first gathered into display order (gatherGroups); withgatherGroups: falsethe data must be pre-sorted by group. Seedocs/llm/DESIGN.md.
Inherited from
gatherGroups
gatherGroups:
boolean
Defined in: base.ts:524
Whether the library gathers non-contiguous groups before rendering
(true, default). Grouping renders contiguous runs, so scattered items
sharing a key would otherwise produce a duplicate label per gap.
true: the DISPLAY order is derived via gatherItemsByGroupKey: groups in first-appearance order, within-group order kept, ungrouped (null-key) items in place. The data itself (items/getItems()) is never reordered, and already-contiguous data is detected in one scan and used as-is.false: strict mode - you guarantee the data is pre-sorted by group; a key reappearing after a gap renders a duplicate label andconsole.warns, so a broken sort is surfaced instead of silently fixed. No effect while grouping is off (every keynull).
Inherited from
groupKeyCompareFn
groupKeyCompareFn: ((
a,b) =>boolean) |null
Defined in: base.ts:534
Equality for two group keys; decides whether items share a group (both
the gatherGroups gather and the contiguous-run rendering use it).
null(default) = identity, the same rule as the defaultcompareFn(===, plusNaNequalsNaN); right for string / number keys.- Supply only when
GroupKeyis an object without usable reference identity. - Mirrors
compareFn, one level up.
Inherited from
groupKeyToStringFn
groupKeyToStringFn: ((
groupKey) =>string) |null
Defined in: base.ts:541
Group key -> the label's display text. The i18n customization point: keep keys stable, translate here.
null(default) =String(groupKey).
Inherited from
groupDisabledFn
groupDisabledFn: ((
groupKey) =>boolean) |null
Defined in: base.ts:549
Predicate: is this whole group disabled?
null(default) = no group disabled.true= every item in the group is treated as disabled (layers on top ofitemDisabledFn).
Inherited from
createGroupLabelContentElFn
createGroupLabelContentElFn: ((
groupKey,itemsInGroup) =>HTMLElement|null) |null
Defined in: base.ts:562
Group label -> its visible content ELEMENT (icon / count badge / rich
markup), without subclassing. Mirrors createItemContentElFn.
- Return an
HTMLElementand the library inserts it as the label's visible content; the group's accessible name staysgroupKeyToString(on the containeraria-label) and the label element staysaria-hidden. null(default, or returned for a group) = plain text fromgroupKeyToString.itemsInGroupis the group's items, so you can render "Fruits (4)" or a summary without recomputing the grouping.
Inherited from
Popup
outsideClickBehavior
outsideClickBehavior:
LLSelectOutsideClickBehavior
Defined in: base.ts:207
See LLSelectOutsideClickBehavior.
Inherited from
popupWidthPolicy
popupWidthPolicy:
LLSelectWidthPolicy
Defined in: base.ts:432
How the popup decides its width. Does NOT affect the trigger - trigger width is always whatever your CSS says.
'fit-content'(default): popup width grows to its own content (items, filter input, ...) and never shrinks below the trigger's width - the native<select>dropdown behavior, minus its viewport overflow: auto-shifts and width-clamps when the natural width would not fit. Direction-aware: in an RTL context (getComputedStyle(trigger).direction === 'rtl', read once per open) it right-aligns to the trigger and grows LEFTWARD, the mirror of LTR.'match-trigger': popup width equals trigger width; long item text wraps inside the popup.
Inherited from
Disabling
itemDisabledFn
itemDisabledFn: ((
item) =>boolean) |null
Defined in: base.ts:442
Predicate deciding whether an individual item is disabled. null (default)
= nothing disabled. A disabled item is not selectable (click / Enter) and is
skipped by keyboard nav; it keeps role="option" plus aria-disabled.
Re-evaluated on every render (never cached). For a generic T this is the
only way to mark items - the library cannot read a disabled field off an
unknown type. See docs/llm/DESIGN.md.
Inherited from
focusableWhenDisabled
focusableWhenDisabled:
boolean
Defined in: base.ts:450
When the control is disabled via setDisabled(true), whether the trigger
stays in the tab order (tabindex="0"). false (default) takes it out
(-1). Set true so keyboard / AT users can focus the disabled control to
read a "why disabled" tooltip.
Inherited from
i18n
uiTranslationPack
uiTranslationPack:
LLSelectUiTranslationPack
Defined in: base.ts:275
Chrome strings (AT labels + generated text): the i18n customization point. Resolved
against English: pass a language pack whole (uiTranslationPack: zhTW from
@llselect/core/i18n) or override single keys
(uiTranslationPack: { ...zhTW, filterInputPlaceholder: '...' }).
Key-by-key contract (incl. what null means where allowed):
LLSelectUiTranslationPack.
Inherited from
CSS
cssClassPrefix
cssClassPrefix:
string
Defined in: base.ts:135
Prefix used for every CSS class and DOM id the library generates
(default 'llselect'). NOTE: the shipped themes target the default
prefix only - a custom prefix means bringing your own CSS. Reference the
resolved names via instance.classIdMap instead of hardcoding strings.
Inherited from
Action rows
popupListLeadingActionRows
popupListLeadingActionRows: readonly
LLSelectPopupListActionRow[]
Defined in: base.ts:372
Commands rendered as role="option" rows at the TOP of the option list,
after the choose-all row when there is one, in array order.
- Each entry is a LLSelectPopupListActionRow. The library builds the row elements and wires them into the arrow-key ring: Home / End reach the ring's ends, disabled rows are skipped, and the popup opens with the active option on an item or the choose-all row, never on one of these rows.
- Rows scroll with the items unless their block is pinned
(
popupListLeadingRowsPinned). For content that is not a command, usecreatePopupHeaderContentElFn/createPopupFooterContentElFn. - Default
[]. The array is copied at construction; later changes to your array do nothing. - Assistive technology announces a row as an option with its text and a positional count; it has no selected state. If the command changes the selection, say so in the row text or a live region.
- A "select all" placed here is a command, not the choose-all row: call
toggleAllVisible()fromonActivateand count withgetVisibleEnabledItems()(both onLLSelectMultiple). It has no selected state and is never the active option when the popup opens. For a row with selection state, usechooseAllRow. - Contract:
docs/llm/A11Y.md"Action rows"; design:docs/llm/DESIGN.md.
Inherited from
popupListTrailingActionRows
popupListTrailingActionRows: readonly
LLSelectPopupListActionRow[]
Defined in: base.ts:382
Commands rendered as role="option" rows at the BOTTOM of the option
list, after the last item, in array order. Same contract as
popupListLeadingActionRows.
- While the filter is active, Home / End move the text caret, so a row down here is reached only by arrowing past every match: put commands keyboard users need often in the leading rows.
Inherited from
popupListLeadingRowsPinned
popupListLeadingRowsPinned:
boolean
Defined in: base.ts:405
Keep the leading rows in view while the items scroll.
- The leading rows are the choose-all row (when on) plus
popupListLeadingActionRows. Withtrue, that whole block sticks to the top edge of the listbox and the items scroll under it. - The rows stay in the arrow-key ring, keep their roles, and are still counted by assistive technology. Only their scrolling changes.
- The library wraps the block in a
divwithrole="presentation"(popupListPinnedLeadingRowsEl, classpopupListPinnedLeadingRowsClass) and setsposition: stickyandtop: 0on it inline, so the setting works in any theme. The shipped themes give the wrapper an opaque background and its edge line. - When the block has no rows, for example when the choose-all row hides because nothing is selectable and there are no leading action rows, the wrapper is not in the listbox.
- Scrolling an item into view accounts for the wrapper's height. When the pinned blocks leave no room for the items, scrolling is best-effort.
- Default
false: the rows scroll with the items. - Pinning is per block, never per row. Why:
docs/llm/popup-rows-and-callbacks.mdsection 5. Contract:docs/llm/A11Y.md"Action rows".
Inherited from
popupListTrailingRowsPinned
popupListTrailingRowsPinned:
boolean
Defined in: base.ts:416
Keep the trailing rows in view while the items scroll.
- The trailing rows are
popupListTrailingActionRows. Withtrue, that block sticks to the bottom edge of the listbox. - Same contract as popupListLeadingRowsPinned. The wrapper is
popupListPinnedTrailingRowsEl, classpopupListPinnedTrailingRowsClass, withbottom: 0. - Default
false.
Inherited from
Choose-all
chooseAllRow
chooseAllRow:
boolean
Defined in: multiple.ts:142
Whether the popup shows a choose-all row (the industry's "select all") as the first option of the listbox.
- Default
false. - Activating the row (Enter, click, or Space while the filter is off)
runs
toggleAllVisible: it toggles the itemsgetVisibleEnabledItems()returns; that method's docstring defines exactly which items those are. The publicchooseAll/unchooseAll/toggleAllkeep their whole-list semantics. - The row is tri-state (none / some / all chosen), carried by the
counting text's numbers and the
data-chosen-stateCSS hook. - Its accessible name comes from
uiTranslationPack.chooseAllRowText. - See
docs/llm/A11Y.md"Choose-all".
createChooseAllRowContentElFn
createChooseAllRowContentElFn: ((
chosenState,chosenCount,totalCount) =>HTMLElement|null) |null
Defined in: multiple.ts:158
The choose-all row's visible content ELEMENT, without subclassing - e.g.
a tri-state SVG checkbox (createOutlinedCheckboxSvgEl) + the counting text. Mirrors
createItemContentElFn. Only used with chooseAllRow: true.
- Receives the tri-state and the counts of the visible enabled subset.
- Return an
HTMLElement: inserted as the row's content; the accessible name stays pinned touiTranslationPack.chooseAllRowTextviaaria-label, so icon-only content is still announced with the counts. null(setting default, or returned): the default content - just the plain counting text; its numbers carry the tri-state. The library ships no default indicator (consistent with items and the arrow); passing this setting is how one (e.g.createOutlinedCheckboxSvgEl) gets added. See DESIGN.md "Choose-all default: plain counting text".
Popup slots
createPopupHeaderContentElFn
createPopupHeaderContentElFn: ((
ctx) =>HTMLElement|null) |null
Defined in: base.ts:335
Content for a pinned header above the option list, without subclassing.
- The library calls it ONCE, inside the constructor, before
newreturns. The variable that will hold the instance is still empty: do not read it in this function. Event handlers on the returned element may read it, because they run afternewreturns. ctxis a LLSelectConstructionContext:classIdMap(for the theme's classes) anduiTranslationPack. That is all this function can safely read.- Return an
HTMLElement: the library wraps it in thepopupHeaderElcontainer (classpopupHeaderClass, no ARIA role) and keeps that node untildestroy().open(),rerender()andsetUiTranslationPack()never rebuild it. Update it yourself, fromonChangeoronOpen. null(setting default, or returned): no header element is built.- Where it sits: between the filter input and the listbox, outside the
scroll area, so it never scrolls with the items. To put it above the
filter input, move it from a subclass constructor:
if (this.popupHeaderEl) { this.popupEl.prepend(this.popupHeaderEl) }. The library never rewrites the popup's child list. A header above the filter input should hold no focusable controls, or Shift+Tab from the input lands in it instead of leaving the widget. - Pointer: a click inside keeps DOM focus on the combobox host (the popup
mousedownrule), so a button works without stealing keyboard input. A text field inside must callstopPropagationon its ownmousedown. - Keep it compact: a long unwrapped line widens a
'fit-content'popup, and a tall slot squeezes the list, the only child that flexes. - Contract:
docs/llm/DESIGN.md"Popup header / footer slots"; keyboard and focus rules:docs/llm/A11Y.md.
Inherited from
createPopupFooterContentElFn
createPopupFooterContentElFn: ((
ctx) =>HTMLElement|null) |null
Defined in: base.ts:347
Content for a pinned footer below the option list, without subclassing.
- Same contract as createPopupHeaderContentElFn: called once in
the constructor with a LLSelectConstructionContext, wrapped in
the
popupFooterElcontainer (classpopupFooterClass, no ARIA role), never rebuilt by the library. null(setting default, or returned): no footer element is built.- Where it sits: after the no-results message, at the bottom of the popup, outside the scroll area.
Inherited from
LLSelectBaseSettings.createPopupFooterContentElFn
LLSelectMultipleSettingsInput
LLSelectMultipleSettingsInput<
T,GroupKey> =LLSelectSettingsInputOf<LLSelectMultipleSettings<T,GroupKey>>
Defined in: multiple.ts:168
Constructor-time settings input for LLSelectMultiple. Every field is optional; missing fields use defaults.
Type Parameters
| Type Parameter | Default type |
|---|---|
T |
- |
GroupKey |
string |
Pack contract
LLSelectUiTranslationPack
Re-exports LLSelectUiTranslationPack
Icons
Shared
LLSelectIconOptions
Defined in: icons.ts:16
Options accepted by the built-in icon helpers.
Extended by
Properties
size?
optionalsize?:number
Defined in: icons.ts:18
Width and height of the SVG in pixels. Default 16.
Arrows
createTriangleDownSvgEl()
createTriangleDownSvgEl(
opts?):SVGElement
Defined in: icons.ts:42
Solid filled triangle pointing down. Sized to roughly match the chevron's
visual weight (MDI's arrow_drop_down path occupies a small portion of
its 24x24 viewBox and looks too small next to other icons).
Parameters
| Parameter | Type |
|---|---|
opts |
LLSelectIconOptions |
Returns
SVGElement
createChevronDownSvgEl()
createChevronDownSvgEl(
opts?):SVGElement
Defined in: icons.ts:51
Material Design expand_more chevron pointing down (filled outline).
Parameters
| Parameter | Type |
|---|---|
opts |
LLSelectIconOptions |
Returns
SVGElement
Checkmarks & checkboxes
createCheckmarkSvgEl()
createCheckmarkSvgEl(
opts?):SVGElement
Defined in: icons.ts:65
Standalone checkmark (no box). Useful as a "selected" indicator in single mode, or as a lightweight chosen marker in multi mode.
Parameters
| Parameter | Type |
|---|---|
opts |
LLSelectIconOptions |
Returns
SVGElement
LLSelectCheckboxState
LLSelectCheckboxState =
"unchecked"|"checked"|"indeterminate"
Defined in: icons.ts:80
Visual state of createOutlinedCheckboxSvgEl / createFilledCheckboxSvgEl.
indeterminate is the "mixed" / partial state used by a choose-all control
(aria-checked="mixed").
LLSelectCheckboxIconOptions
Defined in: icons.ts:100
Options accepted by createOutlinedCheckboxSvgEl and createFilledCheckboxSvgEl.
Extends
Properties
size?
optionalsize?:number
Defined in: icons.ts:18
Width and height of the SVG in pixels. Default 16.
Inherited from
state?
optionalstate?:"some"|"none"|LLSelectCheckboxState|"all"
Defined in: icons.ts:109
Which checkbox state to draw. Accepts the icon vocabulary
('unchecked' | 'checked' | 'indeterminate') or, as a convenience, the
choose-all row's chosen-state vocabulary ('none' -> unchecked,
'some' -> indeterminate, 'all' -> checked), so
createChooseAllRowContentElFn can pass its state straight through.
Default 'unchecked'.
createOutlinedCheckboxSvgEl()
createOutlinedCheckboxSvgEl(
opts?):SVGElement
Defined in: icons.ts:126
Outlined checkbox icon: box border with the tick (checked) / dash
(indeterminate) drawn inside, all in currentColor; the filled twin is
createFilledCheckboxSvgEl. Intended for multi-select item rows and
the choose-all control. Decorative only (aria-hidden); the real state is
carried by aria-selected on the item or aria-checked on the control.
Parameters
| Parameter | Type |
|---|---|
opts |
LLSelectCheckboxIconOptions |
Returns
SVGElement
createFilledCheckboxSvgEl()
createFilledCheckboxSvgEl(
opts?):SVGElement
Defined in: icons.ts:151
Material-look checkbox icon: a solid rounded box with the tick (checked)
/ dash (indeterminate) cut out; unchecked draws the same outline box as
createOutlinedCheckboxSvgEl. Same options, including the chosen-state
vocabulary. Decorative only (aria-hidden); the real state is carried by
aria-selected on the item or aria-checked on the control.
Parameters
| Parameter | Type |
|---|---|
opts |
LLSelectCheckboxIconOptions |
Returns
SVGElement
Positioning
LLSelectPlacement
LLSelectPlacement =
"below"|"above"
Defined in: positioning.ts:18
Whether the floating element sits below or above the anchor.
LLSelectWidthPolicy
LLSelectWidthPolicy =
"fit-content"|"match-trigger"
Defined in: positioning.ts:25
How the floating element decides its width. See LLSelectBaseSettings
(popupWidthPolicy field) for the user-facing contract.
CSS & DOM
LLSelectClassIdMap
Defined in: base.ts:620
Resolved CSS class names and DOM ids for one instance. Exposed on
instance.classIdMap so callers can reuse them in their own CSS or query
selectors instead of hard-coding the strings.
Properties
rootClass
rootClass:
string
Defined in: base.ts:622
Class on rootEl (the caller-passed mount element).
triggerClass
triggerClass:
string
Defined in: base.ts:628
Class on triggerEl (the interactive trigger). Its role is
combobox while the filter is inactive and button while a filterable popup
is open; see docs/llm/A11Y.md.
triggerContentClass
triggerContentClass:
string
Defined in: base.ts:630
Class on the inner span where content (text/tags) is rendered.
triggerArrowClass
triggerArrowClass:
string
Defined in: base.ts:632
Class on the inner span where the optional dropdown arrow lives.
triggerClearButtonClass
triggerClearButtonClass:
string
Defined in: base.ts:634
Class on the clear (x) button slot in the trigger (clearable).
popupClass
popupClass:
string
Defined in: base.ts:636
Class on popupEl (the outer popup wrapper, no ARIA role).
popupListClass
popupListClass:
string
Defined in: base.ts:638
Class on popupListEl (the inner element with role="listbox").
popupListNoResultsClass
popupListNoResultsClass:
string
Defined in: base.ts:643
Class on the no-results message element (role="status"), shown below
the (empty) listbox when the visible item list has zero entries.
popupHeaderClass
popupHeaderClass:
string
Defined in: base.ts:649
Class on popupHeaderEl, the pinned header container between the filter
input and the listbox. The element exists only when header content was
built (createPopupHeaderContentElFn, or a createPopupHeaderEl override).
popupFooterClass
popupFooterClass:
string
Defined in: base.ts:654
Class on popupFooterEl, the pinned footer container at the bottom of
the popup. Exists only when footer content was built.
popupListActionRowClass
popupListActionRowClass:
string
Defined in: base.ts:660
Class on every action row (popupListLeadingActionRows /
popupListTrailingActionRows). Also carries itemClass, so hover /
focused / disabled styling comes from there.
popupListPinnedLeadingRowsClass
popupListPinnedLeadingRowsClass:
string
Defined in: base.ts:665
Class on popupListPinnedLeadingRowsEl, the sticky wrapper around the
leading rows when popupListLeadingRowsPinned is on.
popupListPinnedTrailingRowsClass
popupListPinnedTrailingRowsClass:
string
Defined in: base.ts:670
Class on popupListPinnedTrailingRowsEl, the sticky wrapper around the
trailing rows when popupListTrailingRowsPinned is on.
chooseAllRowClass
chooseAllRowClass:
string
Defined in: base.ts:676
Class on the choose-all row (LLSelectMultiple, chooseAllRow
setting). Also carries itemClass plus data-chosen-state="none|some|all"
for the tri-state visual.
itemClass
itemClass:
string
Defined in: base.ts:678
Class on every item element (role="option") inside the popup list.
itemFocusedClass
itemFocusedClass:
string
Defined in: base.ts:683
Extra class added to the currently keyboard-focused item element. Use this to style the focused item.
itemDisabledClass
itemDisabledClass:
string
Defined in: base.ts:688
Class added to a disabled item element (which also carries
aria-disabled="true"). A stable hook for styling / tooltip targeting.
groupClass
groupClass:
string
Defined in: base.ts:693
Class on a group container (role="group"). A disabled group's container
also carries aria-disabled="true" + data-disabled="true".
groupLabelClass
groupLabelClass:
string
Defined in: base.ts:698
Class on the visible group label element (aria-hidden), inside the group
container above its items. A hook for styling / sticky labels.
tagsClass
tagsClass:
string
Defined in: base.ts:700
Class on the tag-list container in triggerDisplay: 'tags' mode (multi).
tagClass
tagClass:
string
Defined in: base.ts:702
Class on one tag chip (triggerDisplay: 'tags').
tagRemoveButtonClass
tagRemoveButtonClass:
string
Defined in: base.ts:704
Class on a tag's remove (x) button; aria-label names the item, tabindex="-1".
tagDisabledClass
tagDisabledClass:
string
Defined in: base.ts:710
Class on a tag chip whose item is effectively disabled (which also carries
aria-disabled="true", and whose x button no longer removes it). Mirrors
itemDisabledClass; a stable hook for greying the inert chip.
openClass
openClass:
string
Defined in: base.ts:716
Class added to rootEl while the popup is open. Use it as a CSS hook
for open-state styling (also available as [data-state='open'] on the
trigger).
triggerId
triggerId:
string
Defined in: base.ts:718
DOM id of triggerEl. Unique across instances.
labelId
labelId:
string
Defined in: base.ts:724
DOM id minted onto the labelEl setting's element when it has none
(the resolved ariaLabelledBy then references it). Unique across
instances. Unused when labelEl is null or already carries an id.
triggerContentId
triggerContentId:
string
Defined in: base.ts:726
DOM id of the trigger content span. Unique across instances.
triggerValueId
triggerValueId:
string
Defined in: base.ts:735
DOM id of the hidden plain-text value span (root-level sibling of the
trigger). Unique across instances. Referenced by the filterable-mode
trigger's aria-labelledby chain so the closed button's accessible name
includes the current value as PLAIN TEXT - rich trigger content (tag
chips with labelled remove buttons) must not leak control names into the
field name (see the ariaLabel / ariaLabelledBy settings).
popupListId
popupListId:
string
Defined in: base.ts:740
DOM id of popupListEl (the inner listbox). Unique across instances.
Referenced by the trigger's aria-controls attribute.
filterInputClass
filterInputClass:
string
Defined in: base.ts:742
Class on the filter input element inside the popup.
filterInputId
filterInputId:
string
Defined in: base.ts:744
DOM id of the filter input. Unique across instances.
Events
LLSelectChangeSource
LLSelectChangeSource =
"user"|"api"
Defined in: base.ts:42
Who initiated a chosen-state change, delivered to onChange as
meta.source.
'user': a pointer or keyboard interaction inside the widget - an option toggle, a tag's remove button, the clear button, the choose-all row.'api': any programmatic call -setChosenItem/setChosenItems,toggleItem, thechoose*bulk ops,setItemsreconciliation.
LLSelectChangeMeta
Defined in: base.ts:50
Extra facts about one onChange firing, as the callback's third argument.
An object on purpose: future fields can be added without breaking the
callback signature.
Properties
source
source:
LLSelectChangeSource
Defined in: base.ts:51
Filtering
createHighlightedTextEl()
createHighlightedTextEl(
text,query,createMatchElFn?):HTMLElement
Defined in: query-highlight.ts:25
Build a detached <span> of text with every query match wrapped for
highlighting.
- Each case-insensitive occurrence of
querybecomes a<mark>element; everything else stays plain text nodes. - Matching mirrors the built-in filter exactly:
toLowerCaseon both sides, no trimming, scanned left to right without overlap. - If
queryis'', the span holds the plain text and no<mark>. createMatchElFnreplaces the default<mark>builder. It receives the matched text and must return a fully built element: the helper inserts it as-is and does not put the text inside for you.- If a custom
filterFndrives your matching, the helper cannot know its match ranges: it always marks plain substring occurrences. - Intended for
createItemContentElFn/createItemContentEl: they re-run on every filter keystroke, so the marks stay in sync with the query. The option's accessible name is unaffected (it comes fromitemToString). - Rare edge: if lower-casing changes the string's length (a Unicode expansion, e.g. dotted capital I, U+0130), the span degrades to plain unmarked text instead of marking wrong ranges.
Parameters
| Parameter | Type |
|---|---|
text |
string |
query |
string |
createMatchElFn? |
(matchedText) => HTMLElement |
Returns
HTMLElement
Grouping
gatherItemsByGroupKey()
gatherItemsByGroupKey<
T,GroupKey>(items,itemToGroupKeyFn,groupKeyCompareFn?): readonlyT[]
Defined in: grouping.ts:27
Stable-bucket items so that every group is contiguous, without touching
the caller's array.
- Groups appear in order of each key's FIRST appearance.
- Within a group, items keep their relative order.
- Items whose key is
null(ungrouped) form their own single-item segment at their walk position; they never merge. - Already-contiguous input is detected in one scan and returned AS-IS (the input array itself, no copy); otherwise a new array is returned.
This is exactly what LLSelectBase runs internally while the
gatherGroups setting is on (the default). Exported for callers who switch
gatherGroups off and gather once themselves (e.g. ahead of many
setItems calls on the same data).
Type Parameters
| Type Parameter | Default type |
|---|---|
T |
- |
GroupKey |
string |
Parameters
| Parameter | Type | Description |
|---|---|---|
items |
readonly T[] |
the item list to gather |
itemToGroupKeyFn |
(item) => GroupKey | null |
item to group key; null = the item is in no group |
groupKeyCompareFn? |
((a, b) => boolean) | null |
key equality; null / omitted = identity (===, plus NaN equals NaN - the rule the internal Map uses; same contract as the groupKeyCompareFn setting) |
Returns
readonly T[]
Metadata
version
constversion:"0.0.9"='0.0.9'
Defined in: index.ts:71
Library version. Mirrors package.json version (smoke-test guarded).
Action rows
LLSelectPopupListActionRow
Defined in: base.ts:81
One app command rendered by the library as a role="option" row inside the
popup list: the entries of popupListLeadingActionRows /
popupListTrailingActionRows.
- The library builds the row element (id,
role="option", classes,aria-label,aria-disabled, click and Enter); this object supplies only the text, the optional rich content, the disabled state and what activation does. textFnis the accessible name, and the visible text when there is no custom content. It is re-read on every row render, so copy can follow app state or a language switch.createContentElFn: rich visible content;null/ omitted = plain text fromtextFn. Put no focusable control inside: the row itself is the control.disabledFn:null/ omitted = never disabled. Re-read on every row render and again at activation. A disabled row is skipped by the arrow keys and cannot be activated.onActivateruns on Enter, on Space while the filter is inactive, and on click. The library changes nothing else: choosing and closing are this callback's job (callsetChosenItems/close()yourself). Synchronous work runs with the change source'user'; a change made after anawaitreports'api'.- Rows are rebuilt on every list render and after every chosen change, so the three functions may read live state. They receive no parameters: close over your instance variable.
Properties
textFn
textFn: () =>
string
Defined in: base.ts:82
Returns
string
createContentElFn?
optionalcreateContentElFn?: (() =>HTMLElement|null) |null
Defined in: base.ts:83
disabledFn?
optionaldisabledFn?: (() =>boolean) |null
Defined in: base.ts:84
onActivate
onActivate: () =>
void
Defined in: base.ts:85
Returns
void
Popup slots
LLSelectConstructionContext
Defined in: base.ts:102
What a settings function may read while the instance is still being built.
- Only two settings functions receive it:
createPopupHeaderContentElFnandcreatePopupFooterContentElFn. The trigger content functions also run during construction, but they get their own data instead and rerun on every render. newhas not returned yet. The variable that will hold the instance is still empty. Do not read it here.classIdMap: the resolved class and id names.uiTranslationPack: the resolved translation pack.- If you need the instance, do that work in an event handler on the element
you return. Handlers run after
newreturns.
Properties
classIdMap
readonlyclassIdMap:Readonly<LLSelectClassIdMap>
Defined in: base.ts:103
uiTranslationPack
readonlyuiTranslationPack:Readonly<LLSelectUiTranslationPack>
Defined in: base.ts:104