@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:643
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:1270
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:1358
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:2605
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:1057
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:1138
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 filterable: true and DOM
focus is still on the filter input at the moment of close (Esc on empty
filter, single-select pick, click on non-focusable area outside), 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:1240
Open if closed, close if open.
Returns
void
isOpened()
isOpened():
boolean
Defined in: base.ts:1256
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:1331
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:2635
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:1391
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:1402
Whether the whole control is disabled.
Returns
boolean
i18n
getUiTranslationPack()
getUiTranslationPack():
Readonly<LLSelectUiTranslationPack>
Defined in: base.ts:1283
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:1304
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:825
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:1205
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:1225
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:650
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:660
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:667
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:684
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:692
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.
classIdMap
readonlyclassIdMap:LLSelectClassIdMap
Defined in: base.ts:697
Resolved class names and ids for this instance.
triggerValueEl
protectedreadonlytriggerValueEl:HTMLElement
Defined in: base.ts:676
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:1438
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:1443
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:1450
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:1457
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:1939
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
withUserChangeSource()
protectedwithUserChangeSource<R>(fn):R
Defined in: base.ts:1959
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
onLeadingRowActivated()
protectedonLeadingRowActivated():void
Defined in: base.ts:1974
Subclass hook: the leading 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:1495
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:1518
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:1535
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:1558
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:1581
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:1611
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,createPopupListLeadingRowEl,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:1710
Build a detached group container: role="group" named by groupKeyToString,
an aria-hidden visible label element, then the group's item elements. The
label content comes from createGroupLabelContentEl (rich header) when
non-null, else the plain label text. aria-disabled + data-disabled when
the group is disabled. Override for full control of the group element
(mirrors createItemEl).
Parameters
| Parameter | Type | Description |
|---|---|---|
key |
GroupKey |
the group's key |
index |
number |
group index in the current render; builds a stable id |
items |
readonly T[] |
the group's items (for rich content / counts) |
itemEls |
HTMLElement[] |
the group's already-built option elements |
Returns
HTMLElement
createGroupLabelContentEl()
protectedcreateGroupLabelContentEl(key,itemsInGroup):HTMLElement|null
Defined in: base.ts:1744
Group header -> 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 headers pass the setting.
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
itemsInGroup |
readonly T[] |
Returns
HTMLElement | null
replacePopupListItemElInDom()
protectedreplacePopupListItemElInDom(item):void
Defined in: base.ts:1759
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:1792
Build the DOM element for one item. The base implementation sets id,
role="option", a click handler, and fills the visible content via
createItemContentEl (which reads createItemContentElFn), falling
back to textContent from itemToString. When the content is
custom (non-null), the option's aria-label is set from itemToString
so the accessible name stays the plain itemToString text. For one-off rich content
(icons etc.) prefer the createItemContentElFn setting; override this only
to control the whole element (tag, extra wiring).
Parameters
| Parameter | Type | Description |
|---|---|---|
item |
T |
the item value |
index |
number |
index in this.items; used to build a stable id so aria-activedescendant can point to this element across re-renders. |
Returns
HTMLElement
createItemContentEl()
protectedcreateItemContentEl(item):HTMLElement|null
Defined in: base.ts:1852
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
createPopupListLeadingRowEl()
protectedcreatePopupListLeadingRowEl():HTMLElement|null
Defined in: base.ts:1950
Optional non-item role="option" row pinned 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 leading row.
LLSelectMultiple builds its choose-all row here (chooseAllRow setting).
Returns
HTMLElement | null
replaceLeadingRowElInDom()
protectedreplaceLeadingRowElInDom():void
Defined in: base.ts:2029
Rebuild the leading 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 leading row is rendered.
Returns
void
createTriggerClearButtonEl()
protectedcreateTriggerClearButtonEl():HTMLElement
Defined in: base.ts:2410
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:2537
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:2712
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
Subclassing: semantics
isEmpty()
protectedisEmpty():boolean
Defined in: base.ts:1545
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:1841
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:1865
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:1883
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:1892
Map a group key to its header display text.
- Default reads
groupKeyToStringFn, elseString(key).
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
Returns
string
isGroupDisabled()
protectedisGroupDisabled(key):boolean
Defined in: base.ts:1900
Whether the whole group key is disabled per groupDisabledFn (false when unset).
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
Returns
boolean
clearSelection()
protectedclearSelection():void
Defined in: base.ts:2551
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:2647
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:1910
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:1982
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:1994
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
focusLeadingRow()
protectedfocusLeadingRow():boolean
Defined in: base.ts:2012
Move keyboard focus onto the leading 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
leading row's click to focus-then-activate (mirroring how item clicks
call setFocusedIndex before onItemActivated) and use it in
focusInitial (the leading row is the listbox's FIRST option).
Returns
boolean
computeTypeaheadClosedStartIndex()
protectedcomputeTypeaheadClosedStartIndex(_list):number
Defined in: base.ts:2347
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:707
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:718
Current item list. Defensive copy of what setItems was given.
focusedIndex
protectedfocusedIndex:number=-1
Defined in: base.ts:726
Index (into 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:736
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:186
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:236
Return the currently chosen items (insertion order).
Returns
readonly T[]
setChosenItems()
setChosenItems(
items):void
Defined in: multiple.ts:252
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:277
Whether the given item is currently chosen (via compareFn).
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
boolean
toggleItem()
toggleItem(
item):void
Defined in: multiple.ts:306
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:340
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:352
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:363
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:390
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 matches the active filter query. If no query is
active, every item is visible. This is the same list as
getVisibleItems. - Enabled: not disabled via
itemDisabledFn, and not in a disabled group.
- Visible: the item matches the active filter query. If no query is
active, every item is visible. This is the same list as
- If all of them are already chosen, it unchooses exactly those.
- Otherwise, it chooses the ones still missing.
- Choices outside that set (filtered-out or disabled) are preserved either way.
- If no filter query is active, the acted-on set is every enabled item,
the same scope as
toggleAll. - 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
Items
getItems()
getItems(): readonly
T[]
Defined in: base.ts:1270
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:1358
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:444
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:1057
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:1138
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 filterable: true and DOM
focus is still on the filter input at the moment of close (Esc on empty
filter, single-select pick, click on non-focusable area outside), 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:1240
Open if closed, close if open.
Returns
void
Inherited from
isOpened()
isOpened():
boolean
Defined in: base.ts:1256
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:1331
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:2635
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:1391
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:1402
Whether the whole control is disabled.
Returns
boolean
Inherited from
i18n
getUiTranslationPack()
getUiTranslationPack():
Readonly<LLSelectUiTranslationPack>
Defined in: base.ts:1283
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:1304
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:1205
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:1225
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:206
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:212
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:650
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:660
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:667
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:684
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:692
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
classIdMap
readonlyclassIdMap:LLSelectClassIdMap
Defined in: base.ts:697
Resolved class names and ids for this instance.
Inherited from
triggerValueEl
protectedreadonlytriggerValueEl:HTMLElement
Defined in: base.ts:676
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:1438
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:1443
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:1450
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
withUserChangeSource()
protectedwithUserChangeSource<R>(fn):R
Defined in: base.ts:1959
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:617
Toggle on click. Multi mode keeps the popup open.
Parameters
| Parameter | Type |
|---|---|
item |
T |
Returns
void
Overrides
onLeadingRowActivated()
protectedonLeadingRowActivated():void
Defined in: multiple.ts:696
Activate the choose-all row: delegates to toggleAllVisible.
Returns
void
Overrides
onItemsChanged()
protectedonItemsChanged():void
Defined in: multiple.ts:730
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:1495
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:1518
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:1535
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:1581
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:1611
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,createPopupListLeadingRowEl,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:1710
Build a detached group container: role="group" named by groupKeyToString,
an aria-hidden visible label element, then the group's item elements. The
label content comes from createGroupLabelContentEl (rich header) when
non-null, else the plain label text. aria-disabled + data-disabled when
the group is disabled. Override for full control of the group element
(mirrors createItemEl).
Parameters
| Parameter | Type | Description |
|---|---|---|
key |
GroupKey |
the group's key |
index |
number |
group index in the current render; builds a stable id |
items |
readonly T[] |
the group's items (for rich content / counts) |
itemEls |
HTMLElement[] |
the group's already-built option elements |
Returns
HTMLElement
Inherited from
createGroupLabelContentEl()
protectedcreateGroupLabelContentEl(key,itemsInGroup):HTMLElement|null
Defined in: base.ts:1744
Group header -> 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 headers pass the setting.
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
itemsInGroup |
readonly T[] |
Returns
HTMLElement | null
Inherited from
replacePopupListItemElInDom()
protectedreplacePopupListItemElInDom(item):void
Defined in: base.ts:1759
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:1852
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
replaceLeadingRowElInDom()
protectedreplaceLeadingRowElInDom():void
Defined in: base.ts:2029
Rebuild the leading 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 leading row is rendered.
Returns
void
Inherited from
createTriggerClearButtonEl()
protectedcreateTriggerClearButtonEl():HTMLElement
Defined in: base.ts:2410
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:2537
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:2712
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
renderTriggerContent()
protectedrenderTriggerContent():void
Defined in: multiple.ts:472
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:498
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:516
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:548
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:578
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:590
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
createPopupListLeadingRowEl()
protectedcreatePopupListLeadingRowEl():HTMLElement|null
Defined in: multiple.ts:638
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:682
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:704
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:1841
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:1865
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:1883
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:1892
Map a group key to its header display text.
- Default reads
groupKeyToStringFn, elseString(key).
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
Returns
string
Inherited from
isGroupDisabled()
protectedisGroupDisabled(key):boolean
Defined in: base.ts:1900
Whether the whole group key is disabled per groupDisabledFn (false when unset).
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
Returns
boolean
Inherited from
matchesQuery()
protectedmatchesQuery(item,query):boolean
Defined in: base.ts:2647
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
getVisibleEnabledItems()
protectedgetVisibleEnabledItems(): readonlyT[]
Defined in: multiple.ts:414
Return the visible enabled subset: the items toggleAllVisible and the
choose-all row act on.
- It is
getVisibleItems()minus the effectively disabled items (itemDisabledFn, disabled groups). - Both the choose-all row (its counts, tri-state, and click) and
toggleAllVisibleread this one method, so an override keeps them in agreement. Example: the tree-select demo subclass narrows it to leaf nodes.
Returns
readonly T[]
itemToTagRemoveButtonAriaLabel()
protecteditemToTagRemoveButtonAriaLabel(item):string
Defined in: multiple.ts:601
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:609
No selection iff the chosen set is empty. Drives the trigger's data-empty.
Returns
boolean
Overrides
clearSelection()
protectedclearSelection():void
Defined in: multiple.ts:625
Clear button empties the chosen-items set to [].
Returns
void
Overrides
Subclassing: focus
findNextEnabledIndex()
protectedfindNextEnabledIndex(start,step,list):number
Defined in: base.ts:1910
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:1994
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
focusLeadingRow()
protectedfocusLeadingRow():boolean
Defined in: base.ts:2012
Move keyboard focus onto the leading 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
leading row's click to focus-then-activate (mirroring how item clicks
call setFocusedIndex before onItemActivated) and use it in
focusInitial (the leading row is the listbox's FIRST option).
Returns
boolean
Inherited from
computeTypeaheadClosedStartIndex()
protectedcomputeTypeaheadClosedStartIndex(_list):number
Defined in: base.ts:2347
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:764
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:707
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:718
Current item list. Defensive copy of what setItems was given.
Inherited from
focusedIndex
protectedfocusedIndex:number=-1
Defined in: base.ts:726
Index (into 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:736
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:194
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:1270
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:1358
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:2605
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:1057
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:1138
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 filterable: true and DOM
focus is still on the filter input at the moment of close (Esc on empty
filter, single-select pick, click on non-focusable area outside), 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:1240
Open if closed, close if open.
Returns
void
Inherited from
isOpened()
isOpened():
boolean
Defined in: base.ts:1256
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:1331
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:2635
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:1391
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:1402
Whether the whole control is disabled.
Returns
boolean
Inherited from
i18n
getUiTranslationPack()
getUiTranslationPack():
Readonly<LLSelectUiTranslationPack>
Defined in: base.ts:1283
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:1304
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:1205
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:1225
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:650
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:660
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:667
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:684
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:692
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
classIdMap
readonlyclassIdMap:LLSelectClassIdMap
Defined in: base.ts:697
Resolved class names and ids for this instance.
Inherited from
triggerValueEl
protectedreadonlytriggerValueEl:HTMLElement
Defined in: base.ts:676
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:1438
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:1443
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:1450
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
withUserChangeSource()
protectedwithUserChangeSource<R>(fn):R
Defined in: base.ts:1959
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
onLeadingRowActivated()
protectedonLeadingRowActivated():void
Defined in: base.ts:1974
Subclass hook: the leading 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:185
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:244
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:1495
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:1518
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:1535
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:1581
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:1611
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,createPopupListLeadingRowEl,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:1710
Build a detached group container: role="group" named by groupKeyToString,
an aria-hidden visible label element, then the group's item elements. The
label content comes from createGroupLabelContentEl (rich header) when
non-null, else the plain label text. aria-disabled + data-disabled when
the group is disabled. Override for full control of the group element
(mirrors createItemEl).
Parameters
| Parameter | Type | Description |
|---|---|---|
key |
GroupKey |
the group's key |
index |
number |
group index in the current render; builds a stable id |
items |
readonly T[] |
the group's items (for rich content / counts) |
itemEls |
HTMLElement[] |
the group's already-built option elements |
Returns
HTMLElement
Inherited from
createGroupLabelContentEl()
protectedcreateGroupLabelContentEl(key,itemsInGroup):HTMLElement|null
Defined in: base.ts:1744
Group header -> 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 headers pass the setting.
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
itemsInGroup |
readonly T[] |
Returns
HTMLElement | null
Inherited from
replacePopupListItemElInDom()
protectedreplacePopupListItemElInDom(item):void
Defined in: base.ts:1759
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:1852
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
createPopupListLeadingRowEl()
protectedcreatePopupListLeadingRowEl():HTMLElement|null
Defined in: base.ts:1950
Optional non-item role="option" row pinned 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 leading row.
LLSelectMultiple builds its choose-all row here (chooseAllRow setting).
Returns
HTMLElement | null
Inherited from
replaceLeadingRowElInDom()
protectedreplaceLeadingRowElInDom():void
Defined in: base.ts:2029
Rebuild the leading 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 leading row is rendered.
Returns
void
Inherited from
createTriggerClearButtonEl()
protectedcreateTriggerClearButtonEl():HTMLElement
Defined in: base.ts:2410
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:2537
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:2712
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
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:175
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:1841
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:1865
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:1883
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:1892
Map a group key to its header display text.
- Default reads
groupKeyToStringFn, elseString(key).
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
Returns
string
Inherited from
isGroupDisabled()
protectedisGroupDisabled(key):boolean
Defined in: base.ts:1900
Whether the whole group key is disabled per groupDisabledFn (false when unset).
Parameters
| Parameter | Type |
|---|---|
key |
GroupKey |
Returns
boolean
Inherited from
matchesQuery()
protectedmatchesQuery(item,query):boolean
Defined in: base.ts:2647
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:167
No selection iff chosenItem is unset. Drives the trigger's data-empty.
Returns
boolean
Overrides
clearSelection()
protectedclearSelection():void
Defined in: single.ts:194
Clear button empties the single selection to undefined.
Returns
void
Overrides
Subclassing: focus
findNextEnabledIndex()
protectedfindNextEnabledIndex(start,step,list):number
Defined in: base.ts:1910
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:1994
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
focusLeadingRow()
protectedfocusLeadingRow():boolean
Defined in: base.ts:2012
Move keyboard focus onto the leading 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
leading row's click to focus-then-activate (mirroring how item clicks
call setFocusedIndex before onItemActivated) and use it in
focusInitial (the leading row is the listbox's FIRST option).
Returns
boolean
Inherited from
focusInitial()
protectedfocusInitial():void
Defined in: single.ts:203
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:224
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:707
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:718
Current item list. Defensive copy of what setItems was given.
Inherited from
focusedIndex
protectedfocusedIndex:number=-1
Defined in: base.ts:726
Index (into 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:736
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:74
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:149
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:295
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:331
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:108
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:121
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:137
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:406
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:412
Fired right after the popup closes. A no-op close() does not fire it.
Additive with the protected onClosed hook, like onOpen.
Trigger
placeholder
placeholder:
string
Defined in: base.ts:89
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:163
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:188
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:195
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:212
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:234
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:251
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:342
Item -> its group's key (identity), enabling optgroup rendering.
null(setting, default): grouping off - flat list, no headers.- 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:359
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 header 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 header 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:369
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:376
Group key -> the header'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:384
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:397
Group header -> its visible content ELEMENT (icon / count badge / rich
markup), without subclassing. Mirrors createItemContentElFn.
- Return an
HTMLElementand the library inserts it as the header'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:154
popupWidthPolicy
popupWidthPolicy:
LLSelectWidthPolicy
Defined in: base.ts:267
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:277
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:285
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:222
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:82
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.
LLSelectSettingsInputOf
LLSelectSettingsInputOf<
S> =Partial<Omit<S,"uiTranslationPack">> &object
Defined in: base.ts:423
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:433
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:149
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:295
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:331
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:108
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:121
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:137
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:406
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:412
Fired right after the popup closes. A no-op close() does not fire it.
Additive with the protected onClosed hook, like onOpen.
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:89
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:163
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:188
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:195
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:212
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:234
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:251
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:342
Item -> its group's key (identity), enabling optgroup rendering.
null(setting, default): grouping off - flat list, no headers.- 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:359
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 header 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 header 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:369
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:376
Group key -> the header'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:384
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:397
Group header -> its visible content ELEMENT (icon / count badge / rich
markup), without subclassing. Mirrors createItemContentElFn.
- Return an
HTMLElementand the library inserts it as the header'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:154
See LLSelectOutsideClickBehavior.
Inherited from
popupWidthPolicy
popupWidthPolicy:
LLSelectWidthPolicy
Defined in: base.ts:267
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:277
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:285
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:222
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:82
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
LLSelectBaseSettings.cssClassPrefix
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:149
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:295
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:331
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:108
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:121
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:137
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:406
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:412
Fired right after the popup closes. A no-op close() does not fire it.
Additive with the protected onClosed hook, like onOpen.
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:89
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:163
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:188
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:195
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:212
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:234
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:251
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:342
Item -> its group's key (identity), enabling optgroup rendering.
null(setting, default): grouping off - flat list, no headers.- 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:359
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 header 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 header 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:369
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:376
Group key -> the header'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:384
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:397
Group header -> its visible content ELEMENT (icon / count badge / rich
markup), without subclassing. Mirrors createItemContentElFn.
- Return an
HTMLElementand the library inserts it as the header'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:154
See LLSelectOutsideClickBehavior.
Inherited from
popupWidthPolicy
popupWidthPolicy:
LLSelectWidthPolicy
Defined in: base.ts:267
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:277
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:285
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:222
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:82
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
Choose-all
chooseAllRow
chooseAllRow:
boolean
Defined in: multiple.ts:141
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) runs
toggleAllVisible: it toggles the visible enabled subset (the matching subset while a filter query is active). 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:157
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".
LLSelectMultipleSettingsInput
LLSelectMultipleSettingsInput<
T,GroupKey> =LLSelectSettingsInputOf<LLSelectMultipleSettings<T,GroupKey>>
Defined in: multiple.ts:167
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:441
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:443
Class on rootEl (the caller-passed mount element).
triggerClass
triggerClass:
string
Defined in: base.ts:449
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:451
Class on the inner span where content (text/tags) is rendered.
triggerArrowClass
triggerArrowClass:
string
Defined in: base.ts:453
Class on the inner span where the optional dropdown arrow lives.
triggerClearButtonClass
triggerClearButtonClass:
string
Defined in: base.ts:455
Class on the clear (x) button slot in the trigger (clearable).
popupClass
popupClass:
string
Defined in: base.ts:457
Class on popupEl (the outer popup wrapper, no ARIA role).
popupListClass
popupListClass:
string
Defined in: base.ts:459
Class on popupListEl (the inner element with role="listbox").
popupListNoResultsClass
popupListNoResultsClass:
string
Defined in: base.ts:464
Class on the no-results message element (role="status"), shown below
the (empty) listbox when the visible item list has zero entries.
chooseAllRowClass
chooseAllRowClass:
string
Defined in: base.ts:470
Class on the choose-all leading 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:472
Class on every item element (role="option") inside the popup list.
itemFocusedClass
itemFocusedClass:
string
Defined in: base.ts:477
Extra class added to the currently keyboard-focused item element. Use this to style the focused item.
itemDisabledClass
itemDisabledClass:
string
Defined in: base.ts:482
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:487
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:492
Class on the visible group label element (aria-hidden), inside the group
container above its items. A hook for styling / sticky headers.
tagsClass
tagsClass:
string
Defined in: base.ts:494
Class on the tag-list container in triggerDisplay: 'tags' mode (multi).
tagClass
tagClass:
string
Defined in: base.ts:496
Class on one tag chip (triggerDisplay: 'tags').
tagRemoveButtonClass
tagRemoveButtonClass:
string
Defined in: base.ts:498
Class on a tag's remove (x) button; aria-label names the item, tabindex="-1".
tagDisabledClass
tagDisabledClass:
string
Defined in: base.ts:504
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:510
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:512
DOM id of triggerEl. Unique across instances.
labelId
labelId:
string
Defined in: base.ts:518
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:520
DOM id of the trigger content span. Unique across instances.
triggerValueId
triggerValueId:
string
Defined in: base.ts:529
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:534
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:536
Class on the filter input element inside the popup.
filterInputId
filterInputId:
string
Defined in: base.ts:538
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.8"='0.0.8'
Defined in: index.ts:69
Library version. Mirrors package.json version (smoke-test guarded).