Changelog Azalea Kit UI 101 Usage Customizing Utilities Form controls Laravel Vue FHIR Types Accessibility Icons Actions Button Button group Layout and structure Card Card section Care summary Care timeline Divider Empty state Footer Header Layout Stack Table Selection and input Calendar Checkbox Checkbox group Color picker Combobox Combobox option Input Input mask Memorable date Number input Option Phone input Radio Radio button Radio group Range Select SSN input Tag Textarea Toggle ZIP code input Images and icons Avatar Icon Icon button Logo Feedback indicators Badge Banner Progress bar Skeleton Skeleton body text Skeleton display text Skeleton thumbnail Spinner Typography Text Navigation Breadcrumb Breadcrumb item Dropdown Menu Menu item Menu label Navigation Nav group Nav item Nav toggle Pagination Tab Tab group Tab panel Top bar Tree Tree item User menu Overlays Dialog Popover Tooltip Utilities Collapsible FHIR address FHIR human name FHIR quantity FHIR questionnaire Format bytes Format date Format number Relative time Resize observer Split panel Tooltip Border Color Shadow Spacing Transition Typography Z-index Contributing Visual Tests Light Dark System

Select

<ahi-select> | AhiSelect

Select lets users choose one or more items from a dropdown menu. Consider select when you have 4 or more options, to avoid cluttering the interface.

Use the label attribute to give the select an accessible label. For labels that contain HTML, use the label slot instead.

Option 1 Option 2 Option 3
<ahi-select label="Select one" placeholder="Select">
  <ahi-option value="option-1">Option 1</ahi-option>
  <ahi-option value="option-2">Option 2</ahi-option>
  <ahi-option value="option-3">Option 3</ahi-option>
</ahi-select>

This component works with standard <form> elements. Please refer to the section on form controls to learn more about form submission and client-side validation.

Examples

Help text

Add descriptive help text to a select with the help-text attribute. For help texts that contain HTML, use the help-text slot instead.

Follow up visit Physical Sick
<ahi-select
  label="Reason for appointment"
  placeholder="Select"
  help-text="If you would like to request an appointment for a different reason, please call your provider for assistance."
>
  <ahi-option value="1">Follow up visit</ahi-option>
  <ahi-option value="2">Physical</ahi-option>
  <ahi-option value="3">Sick</ahi-option>
</ahi-select>

Clearable

Use the clearable attribute to make the control clearable.

Option 1 Option 2 Option 3
<ahi-select label="Select one" placeholder="Select" clearable>
  <ahi-option value="option-1">Option 1</ahi-option>
  <ahi-option value="option-2">Option 2</ahi-option>
  <ahi-option value="option-3">Option 3</ahi-option>
</ahi-select>

Disabled

Use the disabled attribute to disable a select.

Option 1 Option 2 Option 3
<ahi-select label="Select one" placeholder="Select" disabled>
  <ahi-option value="option-1">Option 1</ahi-option>
  <ahi-option value="option-2">Option 2</ahi-option>
  <ahi-option value="option-3">Option 3</ahi-option>
</ahi-select>

Multiple

To allow multiple options to be selected, use the multiple attribute. It’s a good practice to use clearable when this option is enabled. To set multiple values at once, set value to a space-delimited list of values.

Option 1 Option 2 Option 3 Option 4 Option 5 Option 6
<ahi-select label="Multiple options" value="option-1 option-2 option-3" multiple clearable>
  <ahi-option value="option-1">Option 1</ahi-option>
  <ahi-option value="option-2">Option 2</ahi-option>
  <ahi-option value="option-3">Option 3</ahi-option>
  <ahi-divider></ahi-divider>
  <ahi-option value="option-4">Option 4</ahi-option>
  <ahi-option value="option-5">Option 5</ahi-option>
  <ahi-option value="option-6">Option 6</ahi-option>
</ahi-select>

Note that multi-select options may wrap, causing the control to expand vertically. You can use the max-options-visible attribute to control the maximum number of selected options to show at once.

Setting initial values

Use the value attribute to set the initial selection.

When using multiple, the value property is an array of the selected options’ values, and option values may contain any characters — including spaces. Only the value attribute is space-delimited (HTML attributes can’t express arrays), so options whose values contain spaces can’t be preselected from markup; assign an array to the value property instead.

Option 1 Option 2 Option 3
<ahi-select label="Select one" value="option-1 option-2" multiple clearable>
  <ahi-option value="option-1">Option 1</ahi-option>
  <ahi-option value="option-2">Option 2</ahi-option>
  <ahi-option value="option-3">Option 3</ahi-option>
</ahi-select>

Grouping options

Use <ahi-divider> to group listbox items visually.

Group 1 Option 1 Option 2 Option 3 Group 2 Option 4 Option 5 Option 6
<ahi-select label="Grouped options" placeholder="Select one">
  <ahi-menu-label>Group 1</ahi-menu-label>
  <ahi-option value="option-1">Option 1</ahi-option>
  <ahi-option value="option-2">Option 2</ahi-option>
  <ahi-option value="option-3">Option 3</ahi-option>
  <ahi-divider></ahi-divider>
  <ahi-menu-label>Group 2</ahi-menu-label>
  <ahi-option value="option-4">Option 4</ahi-option>
  <ahi-option value="option-5">Option 5</ahi-option>
  <ahi-option value="option-6">Option 6</ahi-option>
</ahi-select>

Placement

The preferred placement of the select’s listbox can be set with the placement attribute. Note that the actual position may vary to ensure the panel remains in the viewport. Valid placements are top and bottom.

Option 1 Option 2 Option 3
<ahi-select label="Opens upward" placement="top">
  <ahi-option value="option-1">Option 1</ahi-option>
  <ahi-option value="option-2">Option 2</ahi-option>
  <ahi-option value="option-3">Option 3</ahi-option>
</ahi-select>

Prefix & suffix

Use the prefix and suffix slots to add presentational icons and text. Avoid slotting in interactive elements, such as buttons, links, etc.

New Option 1 Option 2 Option 3
<ahi-select label="With prefix and suffix" placeholder="Small" clearable>
  <ahi-icon name="home" slot="prefix"></ahi-icon>
  <ahi-badge slot="suffix">New</ahi-badge>
  <ahi-option value="option-1">Option 1</ahi-option>
  <ahi-option value="option-2">Option 2</ahi-option>
  <ahi-option value="option-3">Option 3</ahi-option>
</ahi-select>

Lazy loading options

Lazy loading options is very hard to get right. <ahi-select> largely follows how a native <select> works.

Here are the following conditions:

  • If a <ahi-select> is created without any options, but is given a value attribute, its value will be "", and then when options are added, if any of the options have a value equal to the <ahi-select> value, the value of the <ahi-select> will equal that of the option.

EX: <ahi-select value="foo"> will have a value of "" until <ahi-option value="foo">Foo</ahi-option> connects, at which point its value will become "foo" when submitting.

  • If a <ahi-select multiple> with an initial value has multiple values, but only some of the options are present, it will only respect the options that are present, and if a selected option is loaded in later, AND the value of the select has not changed via user interaction or direct property assignment, it will add the selected option to the form value and to the .value of the select.

This can be hard to conceptualize, so here’s a fairly large example showing how lazy loaded options work with <ahi-select> and <ahi-select multiple> when given initial value attributes.

Bar Baz
Add “foo” option


Add “foo” option

Bar Baz
Add “foo” option


Add “foo” option


Reset Show FormData


<form id="lazy-options-example">
  <div>
    <ahi-select name="select-1" value="foo" label="Single select (with existing options)">
      <ahi-option value="bar">Bar</ahi-option>
      <ahi-option value="baz">Baz</ahi-option>
    </ahi-select>
    <br>
    <ahi-button type="button">Add "foo" option</ahi-button>
  </div>

  <br>

  <div>
    <ahi-select name="select-2" value="foo" label="Single select (with no existing options)">
    </ahi-select>
    <br>
    <ahi-button type="button">Add "foo" option</ahi-button>
  </div>

  <br>

  <div>
    <ahi-select name="select-3" value="foo bar baz" multiple label="Multiple Select (with existing options)">
      <ahi-option value="bar">Bar</ahi-option>
      <ahi-option value="baz">Baz</ahi-option>
    </ahi-select>
    <br>
    <ahi-button type="button">Add "foo" option</ahi-button>
  </div>

  <br>

  <div>
    <ahi-select name="select-4" value="foo" multiple label="Multiple Select (with no existing options)">
    </ahi-select>
    <br>
    <ahi-button type="button">Add "foo" option</ahi-button>
  </div>

  <br><br>

  <div style="display: flex; gap: 16px;">
    <ahi-button type="reset">Reset</ahi-button>
    <ahi-button type="submit" variant="brand">Show FormData</ahi-button>
  </div>

  <br>

  <pre hidden><code id="lazy-options-example-form-data"></code></pre>

  <br>
</form>

<script type="module">
  function addFooOption(e) {
    const addFooButton = e.target.closest("ahi-button[type='button']")

    if (!addFooButton) {
      return
    }

    const select = addFooButton.parentElement.querySelector("ahi-select")
    if (select.querySelector("ahi-option[value='foo']")) {
      // Foo already exists. no-op.
      return
    }

    const option = document.createElement("ahi-option")
    option.setAttribute("value", "foo")
    option.innerText = "Foo"
    select.append(option)
  }

  function handleLazySubmit (event) {
    event.preventDefault()

    const formData = new FormData(event.target)
    const codeElement = document.querySelector("#lazy-options-example-form-data")
    const obj = {}

    for (const key of formData.keys()) {
      const val = formData.getAll(key).length > 1 ? formData.getAll(key) : formData.get(key)
      obj[key] = val
    }

    codeElement.textContent = JSON.stringify(obj, null, 2)
    const preElement = codeElement.parentElement
    preElement.removeAttribute("hidden")
  }

  const container = document.querySelector("#lazy-options-example")
  container.addEventListener("click", addFooOption)
  container.addEventListener("submit", handleLazySubmit)
</script>

Text assistance and mobile keyboards

The search field accepts the same assistance and keyboard attributes as <ahi-input>: autocapitalize, autocomplete, autocorrect, spellcheck, inputmode and enterkeyhint.

The first four default to off, which is what a typeahead wants — the field matches the literal string you type against its options, so a keyboard that rewrites or capitalizes your input makes it search for something you did not ask for. Turn any of them back on if your field is prose rather than an identifier.

<ahi-select label="Client" autocorrect="on" autocapitalize="sentences"></ahi-select>

Use inputmode to raise the right keyboard, and enterkeyhint to label its Enter key:

<ahi-select label="Account number" inputmode="numeric" enterkeyhint="search"></ahi-select>

Bind autocorrect as a string, not a boolean. autocorrect is a boolean IDL attribute whose content attribute is the string "on" or "off". A framework that forces attributes through setAttribute — Vue does — stringifies a bound false to "false", and the HTML spec says any value that is not "off" means on. So :autocorrect="false" would switch autocorrect on, the exact opposite of the intent.

AKU deliberately departs from the spec here: "false" and "0" are read as off, alongside "off". So the mistake is harmless in AKU. It is still clearer to write autocorrect="off", and other custom elements will not be so forgiving.

Importing

Script Bundler

To import this component using a script tag:

<script type="module" src="/path/to/azalea-kit-ui/dist/components/select/select.js"></script>

To import this component using a bundler:

import '@azaleahealth/azalea-kit-ui/dist/components/select/select.js';

Slots

Name Description
(default) The listbox options. Must be <ahi-option> elements. You can use <ahi-divider> to group items visually.
label The select’s label. Alternatively, you can use the label attribute.
prefix Used to prepend an icon or similar element to the select.
clear-icon An icon to use in lieu of the default clear icon.
expand-icon An icon to use in lieu of the default expand icon.
help-text Text that describes how to use the select. Alternatively, you can use the help-text attribute.
error An error message shown once the control is invalid. Plain text can be set with the error property instead; use this slot when the message needs markup.

Learn more about using slots.

Properties

Name Description Type Default
autocapitalize Controls whether and how text entered into the search field is automatically capitalized. 'off' | 'none' | 'on' | 'sentences' | 'words' | 'characters' 'off'
autocomplete Specifies what permission the browser has to autofill the search field. Defaults to off, which is what a typeahead wants: the field matches against the option list, not a saved value. string 'off'
autocorrect Indicates whether the browser’s autocorrect feature is on or off. As an attribute, use "on" or "off"; as a property it is a boolean, matching the platform’s autocorrect IDL attribute. Defaults to off. A typeahead matches the literal string against its options, so a keyboard that rewrites what was typed makes the field search for something the user did not ask for – which is how the identifier uqbdbecame uAndon blur (CORE-631). boolean false
enterkeyhint Used to customize the label or icon of the Enter key on virtual keyboards. 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send' -
inputmode Tells the browser what type of data will be entered into the search field, so it can raise the appropriate virtual keyboard on supportive devices. 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url' -
spellcheck Enables spell checking on the search field. Off by default, for the same reason autocorrect is. boolean false
defaultValue
value
The default value of the form control, set via the value attribute. Primarily used for resetting the form control. When multiple is enabled the attribute form is a space-delimited list, so attribute-authored values must not contain spaces (assign an array to the value property for values that do). string | string[] ''
placeholder Placeholder text to show as a hint when the select is empty. string ''
multiple Allows more than one option to be selected. boolean false
maxOptionsVisible
max-options-visible
The maximum number of selected options to show when multiple is true. After the maximum, ”+n” will be shown to indicate the number of additional items that are selected. Set to 0 to remove the limit. number 3
disabled Disables the select control. boolean false
clearable Adds a clear button when the select is not empty. boolean false
open Indicates whether or not the select is open. You can toggle this attribute to show and hide the menu, or you can use the show() and hide() methods and this attribute will reflect the select’s open state. boolean false
hoist Deprecated. Enabled a fixed positioning strategy to keep the listbox from being clipped by a container with overflow: auto|scroll. The listbox now renders in the browser’s native top layer, which escapes clipping containers on its own, so this has no effect except as a fallback on browsers without Popover API support. Remove it from your markup; no replacement is needed. boolean false
label The select’s label. If you need to display HTML, use the label slot instead. string ''
placement The preferred placement of the select’s menu. Note that the actual placement may vary as needed to keep the listbox inside of the viewport. 'top' | 'bottom' 'bottom'
helpText
help-text
The select’s help text. If you need to display HTML, use the help-text slot instead. string ''
error An error message to show on the control. Setting it makes the control genuinely invalid: it enters the user-invalid state, matches :invalid, and blocks native form submission — which is what a consumer binding a server-side rejection expects. Clearing it clears that validity. Use the error slot instead when the message needs markup rather than plain text. string ''
required The select’s required attribute. boolean false
validity Gets the validity state object - -
validationMessage Gets the validation message - -
value The current value of the control, submitted as a name/value pair with form data. When multiple is enabled, the value is an array of the selected options’ values and option values may contain any characters, including spaces — only the space-delimited value attribute restricts them (see defaultValue). In single mode, assigning an array keeps its first entry. - -
formId
form
By default, form controls are associated with the nearest containing <form> element. This attribute allows you to place the form control outside of a form and associate it with the form that has this id. The form must be in the same document or shadow root for this to work. string ''
form The form the control is associated with, following the native form-control contract: reading returns the associated <form> element (or null if there is none), assigning takes a form id — assign an empty string to restore association with the nearest containing form. HTMLFormElement | null -
updateComplete A read-only promise that resolves when the component has finished updating.

Learn more about properties and attributes.

Events

Name Description Event Detail
ahi-change Emitted when the control’s value changes. -
ahi-clear Emitted when the control’s value is cleared. -
ahi-input Emitted when the control receives input. -
ahi-focus Emitted when the control gains focus. -
ahi-blur Emitted when the control loses focus. -
ahi-show Emitted when the select’s menu opens. -
ahi-after-show Emitted after the select’s menu opens and all animations are complete. -
ahi-hide Emitted when the select’s menu closes. -
ahi-after-hide Emitted after the select’s menu closes and all animations are complete. -
ahi-invalid Emitted when the form control has been checked for validity and its constraints aren’t satisfied. -

Learn more about events.

Methods

Name Description Arguments
show() Shows the listbox. -
hide() Hides the listbox. -
checkValidity() Checks for validity but does not show a validation message. Returns true when valid and false when invalid. -
reportValidity() Checks for validity and shows the browser’s validation message if the control is invalid. -
setCustomValidity() Sets a custom validation message. Pass an empty string to restore validity. message: string
focus() Sets focus on the control. options: FocusOptions
blur() Removes focus from the control. -
resetValidity() Hides validity again, returning the control to its pristine state: it stops matching :user-invalid and drops its error styling until the user next interacts with it. The value and the validity are both untouched — an empty required control is still invalid and still blocks submission. This only changes whether that invalidity is shown. Interaction state otherwise has exactly one automatic exit, form.reset(). Call this when the application replaces a value itself and the old error no longer describes anything the user did: loading a draft, switching which record is being edited, or clearing a filter row. -

Learn more about methods.

CSS Parts

Name Description
form-control The form control that wraps the label, input, and help text.
form-control-label The label’s wrapper.
form-control-input The select’s wrapper.
form-control-help-text The help text’s wrapper.
form-control-error The error’s wrapper.
combobox The container the wraps the prefix, suffix, combobox, clear icon, and expand button.
prefix The container that wraps the prefix slot.
suffix The container that wraps the suffix slot.
display-input The element that displays the selected option’s label, an <input> element.
listbox The listbox container where options are slotted.
tags The container that houses option tags when multiselect is used.
tag The individual tags that represent each multiselect option.
tag__base The tag’s base part.
tag__content The tag’s content part.
tag__remove-button The tag’s remove button.
tag__remove-button__base The tag’s remove button base part.
clear-button The clear button.
expand-icon The container that wraps the expand icon. This control inherits setCustomValidity(message), checkValidity() and reportValidity() from the form-control base class. Because they are inherited rather than declared here, they do not appear in this component’s generated type definitions – which is why they are easy to conclude do not exist. They do, and they work.

Learn more about customizing CSS parts.

Dependencies

This component automatically imports the following dependencies.

  • <ahi-icon>
  • <ahi-icon-button>
  • <ahi-popup>
  • <ahi-tag>