On this page Select Select

The m3e-select component provides a form control for selecting a value from a set of predefined options.

Installation
npm i @m3e/select
Usage

This section outlines usage examples and configuration guidance for the components in this package.

Basic usage

The following example illustrates use of a m3e-select in conjunction with the m3e-form-field. See Form Field for more information.

To define selectable options within a m3e-select, include one or more m3e-option elements as its children. Each m3e-option may specify a value attribute, which determines the programmatic value submitted when the option is selected. The textual content of the m3e-option element represents the label presented to the user in the dropdown interface.

Apples Oranges Bananas Grapes
<m3e-form-field>
  <label slot="label" for="select">Favorite fruit</label>
  <m3e-select id="select">
    <m3e-option>Apples</m3e-option>
    <m3e-option>Oranges</m3e-option>
    <m3e-option>Bananas</m3e-option>
    <m3e-option>Grapes</m3e-option>
  </m3e-select>
</m3e-form-field>
Empty options

To define an empty option, include a m3e-option without a value or content. Alternately, set the value attribute to "" and include descriptive content such as "None". This signals that no meaningful value has been selected. Empty options are commonly used to represent a placeholder or default state prior to user interaction.

None Apples Oranges Bananas Grapes
<m3e-form-field>
  <label slot="label" for="select">Favorite fruit</label>
  <m3e-select id="select">
    <m3e-option value="">None</m3e-option>  
    <m3e-option>Apples</m3e-option>
    <m3e-option>Oranges</m3e-option>
    <m3e-option>Bananas</m3e-option>
    <m3e-option>Grapes</m3e-option>
  </m3e-select>
</m3e-form-field>
Option groups

The m3e-optgroup component can be used to group common options under a subheading. The name of the group can be set using the label slot.

Nested groups are not supported—only a single level of grouping is permitted.

Grass Bulbasaur Oddish Bellsprout Water Squirtle Psyduck Horsea Fire Charmander Vulpix Flareon
<m3e-form-field>
  <label slot="label" for="select">Pokemon</label>
  <m3e-select id="select">
    <m3e-optgroup>
      <span slot="label">Grass</span>
      <m3e-option>Bulbasaur</m3e-option>
      <m3e-option>Oddish</m3e-option>
      <m3e-option>Bellsprout</m3e-option>
    </m3e-optgroup>
    <!-- Additional option groups omitted for brevity -->
  </m3e-select>
</m3e-form-field>
Selection

Selects support both single-select and multi-select modes. Use the multi attribute to allow multiple options to be selected simultaneously.

Use the selected attribute to control the selected state of a m3e-option. When clicked, a cancellable input event is emitted by the m3e-select followed by a change event. To cancel selection change, call preventDefault during input.

Extra cheese Mushroom Onion Pepperoni Sausage Tomato
<m3e-form-field>
  <label slot="label" for="select">Toppings</label>
  <m3e-select id="select" multi>
    <m3e-option selected>Extra cheese</m3e-option>
    <m3e-option selected>Mushroom</m3e-option>
    <!-- Additional option groups omitted for brevity -->
  </m3e-select>
</m3e-form-field>
Disabling

You can disable the entire select component or individual options by applying the disabled attribute to m3e-select or m3e-option, respectively.

Apples Oranges Bananas Grapes
<m3e-form-field>
  <label slot="label" for="select">Favorite fruit</label>
  <m3e-select id="select" disabled>
    <m3e-option selected>Apples</m3e-option>
    <!-- Additional option groups omitted for brevity -->
  </m3e-select>
</m3e-form-field>
Apples Oranges Bananas Grapes
<m3e-form-field>
  <label slot="label" for="select">Favorite fruit</label>
  <m3e-select id="select">
    <m3e-option disabled>Apples</m3e-option>
    <!-- Additional option groups omitted for brevity -->
  </m3e-select>
</m3e-form-field>
Required

Apply the required attribute to enforce selection. This ensures that users must choose at least one option before the field is considered valid. For multi-select configurations, at least one selected option satisfies the requirement.

None Apples Oranges Bananas Grapes
<m3e-form-field>
  <label slot="label" for="select">Favorite fruit</label>
  <m3e-select id="select" required>
    <m3e-option value="">None</m3e-option>  
    <m3e-option>Apples</m3e-option>
    <!-- Additional option groups omitted for brevity -->
  </m3e-select>
</m3e-form-field>
Accessibility

The m3e-select component follows the ARIA combobox interaction pattern. Selects are given the ARIA role="combobox", while the dropdown panel applies role="listbox" to convey its structure to assistive technologies.

Options are given ARIA role="option", indicating that each item represents a selectable choice within a listbox context. This role enables assistive technologies to interpret and announce the options appropriately, supporting accessible navigation and selection behavior.

Option groups are given ARIA role="group", indicating that the grouped options form a semantically related set within the listbox. This role helps assistive technologies convey structural relationships between options, enhancing navigability and contextual understanding for screen reader users.

The aria-selected attribute reflects whether an option is currently selected. When an option is selected, aria-selected="true" is exposed to assistive technologies; otherwise, it is "false".

When disabled using the disabled attribute, aria-disabled="true" is used to convey to assistive technologies that an option or select is disabled. When a m3e-select is disabled at runtime, it does not sprout a disabled attribute into the DOM.

The aria-activedescendant attribute is applied to the m3e-select element to indicate which option is currently active within the listbox. Instead of moving DOM focus to each option, the select retains focus while updating aria-activedescendant to reference the id of the focused m3e-option. This approach preserves focus management and enables assistive technologies to announce the active option during keyboard navigation, ensuring accessible and predictable interaction.

The aria-owns and aria-controls attributes are applied to the m3e-select element to establish an explicit relationship with the listbox popup. Both attributes reference the id of the listbox container, ensuring assistive technologies recognize the connection between the trigger and the controlled content. While aria-controls indicates that the select governs the visibility and behavior of the listbox, aria-owns asserts DOM ownership when the listbox is rendered outside the select's subtree.

The aria-expanded attribute reflects the current state of the listbox popup. When the listbox is open, aria-expanded="true" is set on the m3e-select element; when collapsed, it is set to false. This dynamic state enables screen readers to announce whether the listbox is expanded or collapsed, supporting accessible navigation and interaction.

Because listbox is designed for single-item selection, you should avoid placing additional interactive elements—such as buttons, checkboxes, or toggles—inside m3e-option. Nesting interactive controls within options disrupts expected navigation and interferes with screen reader behavior.

Native module support

This package uses JavaScript Modules. To use it directly in a browser without a bundler, use a module script similar to the following.

<script type="module" src="/node_modules/@m3e/select/dist/index.js"></script>

You also need a module script for @m3e/option due to it being a dependency.

<script type="module" src="/node_modules/@m3e/option/dist/index.js"></script>

In addition, you must use an import map to include additional dependencies.

<script type="importmap">
  {
    "imports": {
      "lit": "https://cdn.jsdelivr.net/npm/lit@3.3.0/+esm",
      "@m3e/core": "/node_modules/@m3e/core/dist/index.js",
      "@m3e/core/a11y": "/node_modules/@m3e/core/dist/a11y.js",
      "@m3e/core/anchoring": "/node_modules/@m3e/core/dist/anchoring.js",
      "@m3e/core/bidi": "/node_modules/@m3e/core/dist/bidi.js"

    }
  }
</script>

For production, use index.min.js, a11y.min.js, anchoring.min.js, and bidi.min.js for faster load times.

API

This package includes a Custom Elements Manifest (custom-elements.json), which documents the properties, attributes, slots, events and CSS custom properties of each component.

You can explore the API below, or integrate the manifest into your own tooling.