ba-select
A form field for giving users a choice from a dropdown
Airframe
Web Components
React
React Native
Anatomy
Label
A short, descriptive text that identifies the purpose of the select field
Hint text (optional)
Additional guidance below the label to help users understand what to select
Select input
The interactive dropdown control that reveals a list of options when activated
Error message
Inline validation feedback that appears when no valid option has been selected
Design Documentation
It is best to use the select component when you have 5 or more options for the user to select from. If you have fewer options to select from, try using ba-radio-group instead.
Where a natural order exists, follow it. For example:
- Alphabetical: Lists of countries, names, etc
- Numerical: Seat numbers, baggage counts, etc
If no clear ordering principle applies (e.g., different methods for downloading a boarding pass), consider:
- Grouping options by category with
<optgroup>elements for example, dividing meal preferences into Vegetarian, Non-Vegetarian, and Special Diet - helps users quickly scan and select the option that suits their needs - Alphabetical ordering if no other logical sequence makes sense
- Short, descriptive labels that clearly differentiate each option
Live Demo
Custom error message
<ba-select
label="Select Label"
hint-text="Help text for the field"
name="name"
prompt-text="Choose an item"
required
>
<p slot="error">Custom error message</p>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
<option value="4">Option 4</option>
<option value="5">Option 5</option>
<option value="6">Option 6</option>
<option value="7">Option 7</option>
<option value="8">Option 8</option>
<option value="9">Option 9</option>
<option value="10">Option 10</option>
</ba-select>
Properties and attributes
| Property | Attribute | Description | Type | Default |
|---|---|---|---|---|
autocomplete |
autocomplete |
The autocomplete setting | string | undefined |
'off' |
hintText |
hint-text |
Hint text to show above the input | string | undefined |
undefined |
iconName |
icon-name |
The name of the icon to show in the media slot. Will be overridden if there is content in the media slot. | string | undefined |
undefined |
inputWidth |
input-width |
The width of the input in characters | string | undefined |
undefined |
invalid |
invalid |
The name of the input | boolean | undefined |
false |
label(required) |
label |
A label for the input | string |
undefined |
name(required) |
name |
The name of the input | string |
undefined |
promptText |
prompt-text |
Text for the default option | string | undefined |
undefined |
required |
required |
Whether the input is required | boolean | undefined |
false |
value |
value |
The value of the input | string | undefined |
'' |
Permitted ARIA roles
- None
Slots
| Slot | Description | Permitted elements |
|---|---|---|
| Unnamed slot | The options for the select will be rendered here | <option> |
"error" |
Element will be rendered in the error slot | <p> |
"media" |
Show an image or icon before the text | <ba‑image>, <img>, <svg> |
Parent components
ba-select can be slotted into:
<ba‑accordion><ba‑card><ba‑card‑segmented><ba‑details><ba‑flex><ba‑form><ba‑form‑group><ba‑form‑group‑dropdown><ba‑grid>
Events
| Event | Description | Type |
|---|---|---|
baBlur |
Emitted when the select loses focus. | CustomEvent<void> |
baChange |
Emitted when the value has changed. | CustomEvent<SelectChangeEventDetail> |
baFocus |
Emitted when the select has focus. | CustomEvent<void> |
Methods
| Method | Description | Type |
|---|---|---|
isValid() => Promise<boolean> |
Triggers required validation and resolves with validity state. | Promise<boolean> |
reset() => Promise<void> |
Resets the select back to its initial value and validity. | Promise<void> |
Usage
Basic usage
The first option will be selected if no prompt-text and value are set, and each option has a value.
This will always pass required validation as value is set via the component internally.
<ba-select
label="Select Label"
hint-text="Help text for the field"
name="name"
required
>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
<option value="4">Option 4</option>
<option value="5">Option 5</option>
<option value="6">Option 6</option>
<option value="7">Option 7</option>
<option value="8">Option 8</option>
<option value="9">Option 9</option>
<option value="10">Option 10</option>
</ba-select>
Setting prompt-text
When the prompt-text has been set this will be selected by the component on page load.
This will fail the required validation as no valid value has been selected.
<ba-select
label="Select Label"
hint-text="Help text for the field"
name="name"
prompt-text="Choose an item"
required
>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
<option value="4">Option 4</option>
<option value="5">Option 5</option>
<option value="6">Option 6</option>
<option value="7">Option 7</option>
<option value="8">Option 8</option>
<option value="9">Option 9</option>
<option value="10">Option 10</option>
</ba-select>
Custom error
You can provide your own custom validation and error message using events, props and slots.
<ba-select
label="Select Label"
hint-text="Help text for the field"
name="name"
prompt-text="Choose an item"
required
>
<p slot="error">Custom error message</p>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
<option value="4">Option 4</option>
<option value="5">Option 5</option>
<option value="6">Option 6</option>
<option value="7">Option 7</option>
<option value="8">Option 8</option>
<option value="9">Option 9</option>
<option value="10">Option 10</option>
</ba-select>
<script>
const baSelect = document.querySelector('ba-select');
baSelect.addEventListener('baChange', (e) => {
const value = e.detail.value;
// Do your custom validation here.
//
//
// Then set the input to invalid
baSelect.setAttribute('invalid')
})
</script>
Updating options via JavaScript
For adding / removing options you need to remove all existing options and re-populate them to ensure the internal state of the component is correctly updated.
Ensure that you are interacting with ba-select and not a wrapped native select element.
<ba-select
label="Select Label"
prompt-text="Choose an item"
>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</ba-select>
<script>
const baSelect = document.querySelector('ba-select');
const currentOptions = baSelect.querySelectorAll('option');
currentOptions.forEach(option => option.remove());
const options = [
{ value: 'a', text: 'Option A' },
{ value: 'b', text: 'Option B' },
{ value: 'c', text: 'Option C' },
];
options.forEach(option => {
const optionElement = document.createElement('option');
optionElement.setAttribute('value', option.value);
optionElement.textContent = option.text;
baSelect.appendChild(optionElement);
});
// Optional, you can set a value after updating options
baSelect.value = 'b';
</script>
Showing an icon
There is an option to show an icon within the select component. Simply add the name of the icon you wish to present in the icon-name prop.
<ba-select
label="Select Label"
hint-text="Help text for the field"
name="name"
required
icon-name="add"
>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</ba-select>
Using the media slot
You can also use the media slot by using a svg, img or ba-image element.
<ba-select
label="Select Label"
hint-text="Help text for the field"
name="name"
required
icon-name="add"
>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
<ba-image slot="media" src="path-to-image"></ba-image>
</ba-select>
Dynamically setting the media slot
You can dynamically change the image based on the user's selection.
<ba-select
label="Select Label"
hint-text="Help text for the field"
name="name"
required
prompt-text="Choose an item"
>
<img src="visa.webp" alt="Visa" id="visa" slot="media" style="display: none;"/>
<img src="mastercard.webp" alt="Mastercard" id="mastercard" slot="media" style="display: none;"/>
<img src="american-express.webp" alt="American Express" id="amex" slot="media" style="display: none;"/>
<img src="apple-pay.webp" alt="Apple Pay" id="apple" slot="media" style="display: none;"/>
<img src="google-pay.webp" alt="Google Pay" id="google" slot="media" style="display: none;"/>
<option value="visa">Visa</option>
<option value="mastercard">Mastercard</option>
<option value="amex">Amex</option>
<option value="apple">Apple Pay</option>
<option value="google">Google Pay</option>
</ba-select>
<script>
(() => {
let previousValue = '';
document.addEventListener('baChange', (event) => {
const paymentType = event.detail.value;
if (previousValue !== '') {
const previousElement = document.getElementById(previousValue);
previousElement.style.display = 'none';
}
if (paymentType !== '') {
const element = document.getElementById(paymentType);
element.style.display = 'block';
previousValue = paymentType;
}
})
})()
</script>
Guidelines
Always use the label attribute to give a meaningful label to the field.
Further reading:
Disabled form elements are not supported in BAgel because they create accessibility challenges, such as preventing keyboard navigation, confusing screen reader users, and reducing visual clarity for those with impairments
Further reading:
Keyboard navigation
State: Previous element in DOM has focus
<ba-select> gets focus
State: <ba-select> has focus
Opens the dropdown list of options
Opens the dropdown list of options
Next tabbable element in the DOM gets focus
State: Dropdown is open
Moves highlight to the previous option
Moves highlight to the next option
Selects the highlighted option, closes the dropdown, and emits baChange
Closes the dropdown without changing the selected value
Usage and accessibility checklist
Use this checklist to confirm the component has been configured and used correctly.
UX checklist
- ba-select is used when there are 5 or more options to choose from
- ba-radio-group is used instead when there are fewer than 5 options
- Options are presented in a meaningful order (alphabetical, numerical, or grouped with optgroup)
- prompt-text is used when the field is required and no default selection should be pre-applied
- Labels are concise and clearly describe what the user is choosing
Accessibility checklist
- A visible label is always provided using the label attribute
- The disabled state is not used — ba-select does not support disabled form controls
- ba-select is keyboard operable and receives a visible focus indicator
- Focus indicator has not been obscured on all sides of the component
These checks are handled by the component and do not need to be repeated each time it is used.
- ba-select is operable using assistive technology
- Has a visible focus indicator on all sides of the component
- Colour contrast for all states in all BAgel themes
- Animations respect users' reduced motion settings
- High contrast mode adjustments