Accessible custom select with single/multi-select, search, keyboard navigation, and extensive customization
Get started with the Select component in 3 simple steps:
The Select component initializes automatically on page load. No additional JavaScript required!
Configure the select component using data attributes. All features are opt-in via attributes.
| Attribute | Type | Default | Description |
|---|---|---|---|
data-rsl-select |
boolean | required | Initializes the element as a select component |
data-rsl-select-name |
string | - | Name attribute for form submission |
data-rsl-select-placeholder |
string | "Select an option..." | Placeholder text when nothing is selected |
data-rsl-select-disabled |
boolean | false | Disables the select |
data-required |
boolean | false | Marks select as required for validation |
| Attribute | Type | Default | Description |
|---|---|---|---|
data-rsl-select-multi |
boolean | false | Enables multi-select mode |
data-rsl-select-show-count |
boolean | true | Show count of selected items in trigger ("3 items selected") |
data-rsl-select-show-chips |
boolean | false | Show selected items as chips/tags (visible by default) |
data-rsl-select-chips-toggle |
boolean | true | Show toggle button to show/hide chips |
data-rsl-select-max-selections |
number | Infinity | Maximum number of items that can be selected |
| Attribute | Type | Default | Description |
|---|---|---|---|
data-rsl-select-searchable |
boolean | false | Enables search/filter input in dropdown |
data-rsl-select-search-placeholder |
string | "Search..." | Placeholder text for search input |
data-rsl-select-no-results |
string | "No results found" | Message shown when search has no results |
| Attribute | Type | Default | Description |
|---|---|---|---|
data-rsl-select-size |
string | "md" | Size variant: "sm", "md", or "lg" |
data-rsl-select-clearable |
boolean | false | Shows clear button (×) when value is selected |
data-rsl-select-max-height |
string | "300px" | Maximum height of dropdown options list |
data-rsl-select-position |
string | "auto" | Dropdown position: "auto", "above", or "below" |
| Attribute | Type | Default | Description |
|---|---|---|---|
data-rsl-select-hidden |
boolean | true | Automatically creates hidden <select> for form submission |
data-rsl-select-onchange |
string | - | Name of callback function to call on value change |
data-rsl-select-onopen |
string | - | Name of callback function to call when dropdown opens |
data-rsl-select-onclose |
string | - | Name of callback function to call when dropdown closes |
data-rsl-select. The component works out-of-the-box with sensible defaults.
Configure individual options using standard <option> elements or data attributes.
| Attribute | Description | Example |
|---|---|---|
value |
The value submitted with the form | <option value="us"> |
data-label |
Custom display label (overrides text content) | data-label="United States" |
data-description |
Secondary description text shown below label | data-description="North America" |
data-icon |
FontAwesome icon class | data-icon="fas fa-flag" |
data-image |
Image URL (circular avatar) | data-image="flags/us.png" |
data-group |
Group name for organizing options | data-group="Americas" |
disabled |
Disables the option | <option disabled> |
selected |
Pre-selects the option | <option selected> |
Programmatically control select components using the RSL.Select API.
| Method | Parameters | Description |
|---|---|---|
RSL.Select.init() |
- | Initialize all selects on the page |
RSL.Select.create(element) |
HTMLElement | Create a select from a specific element |
RSL.Select.getValue(element) |
HTMLElement | Get selected value(s) as array |
RSL.Select.setValue(element, values) |
HTMLElement, Array|String | Set selected value(s) programmatically |
RSL.Select.open(instance) |
Object | Open the dropdown |
RSL.Select.close(instance) |
Object | Close the dropdown |
RSL.Select.clear(instance) |
Object | Clear all selections |
RSL.Select.destroy(element) |
HTMLElement | Destroy select instance and restore original element |
// Get the original select element
var selectElement = document.querySelector('[data-rsl-select]');
// Get current value(s)
var values = RSL.Select.getValue(selectElement);
console.log(values); // ["us", "ca"]
// Set value programmatically
RSL.Select.setValue(selectElement, 'uk');
// Set multiple values
RSL.Select.setValue(selectElement, ['us', 'uk', 'ca']);
// Listen for changes
selectElement.addEventListener('rsl-select-change', function(e) {
console.log('Selected:', e.detail.values);
console.log('Options:', e.detail.options);
});
The Select component supports bidirectional FilterBus integration - it can both publish selection changes to control other components AND subscribe to filter state changes to update its own selection or visibility.
| Attribute | Type | Description |
|---|---|---|
data-filterbus-publish |
String | FilterBus key to publish selection changes to. When user selects an option, publishes the value to this key. |
data-filterbus-subscribe |
String | FilterBus key to subscribe to. Updates selection when this key changes (for syncing with other components). |
data-filter-value |
String | For visibility filtering - shows/hides the select based on filter match. Supports comma-separated values. |
Use a Select as a filter control that drives other components:
<!-- Select publishes region changes to FilterBus -->
<div data-rsl-select
data-filterbus-publish="region"
data-rsl-select-placeholder="Select Region...">
<option value="All">All Regions</option>
<option value="North">North Region</option>
<option value="South">South Region</option>
<option value="East">East Region</option>
<option value="West">West Region</option>
</div>
<!-- KPI Cards subscribe to the region filter -->
<div data-rsl-kpi-card
data-filterbus-subscribe="region"
data-filter-value="North">
<!-- This card shows only when "North" or "All" is selected -->
</div>
Sync a Select's selection with another filter control:
<!-- Filter buttons publish to "region" key -->
<div data-rsl-filter data-filter-key="region">
<button data-filter-value="All">All</button>
<button data-filter-value="North">North</button>
<button data-filter-value="South">South</button>
</div>
<!-- This select syncs with the filter buttons -->
<div data-rsl-select
data-filterbus-subscribe="region"
data-rsl-select-placeholder="Select Region...">
<option value="All">All Regions</option>
<option value="North">North Region</option>
<option value="South">South Region</option>
</div>
Show/hide a Select based on another filter:
<!-- This select only shows when category is "Advanced" -->
<div data-rsl-select
data-filterbus-subscribe="category"
data-filter-value="Advanced"
data-rsl-select-placeholder="Advanced Options...">
<option value="opt1">Option 1</option>
<option value="opt2">Option 2</option>
</div>
| Method | Description |
|---|---|
RSL.Select.initFilterBus(element) |
Initialize FilterBus for a specific select element |
RSL.Select.destroyFilterBus(element) |
Remove FilterBus subscription and reset visibility |
RSL.Select.filterSubscriptions |
Map of active FilterBus subscriptions (element → subscriberId) |
| Event | Detail | Description |
|---|---|---|
rsl-select:filterbus-update |
{ state, meta } |
Fired when select receives a FilterBus state update |
The Select component is fully WCAG 2.1 AA compliant with comprehensive accessibility features built-in.
| Key | Action |
|---|---|
Space / Enter |
Open dropdown (when focused on trigger) |
↓ Arrow Down |
Navigate to next option |
↑ Arrow Up |
Navigate to previous option |
Home |
Jump to first option |
End |
Jump to last option |
Enter / Space |
Select focused option |
Escape |
Close dropdown and return focus to trigger |
Tab |
Close dropdown and move to next focusable element |
Character keys |
Type-ahead: jump to option starting with typed character |
The component automatically manages all necessary ARIA attributes:
role="listbox" on dropdownrole="option" on each optionaria-haspopup="listbox" on triggeraria-expanded indicates dropdown statearia-selected indicates selected optionsaria-disabled on disabled optionsaria-multiselectable for multi-selectaria-label with descriptive text for all interactive elements| Browser | Version | Status |
|---|---|---|
| Chrome | 90+ | ✓ Full Support |
| Firefox | 88+ | ✓ Full Support |
| Safari | 14+ | ✓ Full Support |
| Edge | 90+ | ✓ Full Support |
| Mobile Safari | iOS 14+ | ✓ Full Support |
| Chrome Mobile | Android 8+ | ✓ Full Support |
View examples.html for comprehensive demos
Test features in playground.html
Browse all RSL components