Select Components

Standard Select Demo

				
					
<!-- Container for the Single Select -->
<div class="select-container">
    <!-- Label for the Single Select -->
    <label for="singleSelect">Single Select</label>
    <!-- Single Select element -->
    <select id="singleSelect" class="single-select" aria-label="Single Select" role="listbox">
        <!-- Options for single select -->
        <option value="option1">Option 1</option>
        <option value="option2">Option 2</option>
        <!-- Add more options here -->
    </select>
</div>

				
			
				
					
/* Set the brand colors */
:root {
  --main-color: #005e86;
  --secondary-color: #99b4c0;
  --accent-color: #211224;
}

/* Basic styles */
body {
  font-family: 'Barlow', sans-serif;
}

/* Select rows and containers */
.select-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  margin-bottom: 20px;
}

.select-container {
  width: calc(40% - 10px); /* Adjust as needed */
  margin-bottom: 10px;
  position: relative;
  box-sizing: border-box;
}

/* Select styling */
select,
input[type="text"] {
  width: calc(100% - 2px);
  padding: 8px;
  border: 1px solid var(--main-color);
  border-radius: 5px;
  font-family: inherit;
  font-size: 14px;
}
				
			

Multi-Select Demo

				
					
<!-- Container for the Multi-Select -->
<div class="select-container">
    <!-- Label for the Multi-Select -->
    <label for="multiSelect">Multi Select</label>
    <!-- Multi-Select element -->
    <select id="multiSelect" class="multi-select" aria-label="Multi Select" multiple="multiple" role="listbox">
        <!-- Options for multi-select -->
        <option value="option1">Option 1</option>
        <option value="option2">Option 2</option>
        <option value="option3">Option 3</option>
        <option value="option4">Option 4</option>
        <option value="option5">Option 5</option>
        <!-- Add more options here -->
    </select>
</div>
				
			
				
					
/* Set the brand colors */
:root {
  --main-color: #005e86;
  --secondary-color: #99b4c0;
  --accent-color: #211224;
}

/* Basic styles */
body {
  font-family: 'Barlow', sans-serif;
}

/* Select rows and containers */
.select-row {
  display: flex;
  justify-content: space-between;
  margin-bottom: 20px;
}

.select-container {
  width: 45%;
  position: relative;
}

/* Select styling */
select, input[type="text"] {
  width: 100%;
  padding: 8px;
  border: 1px solid var(--main-color);
  border-radius: 5px;
  font-family: inherit;
  font-size: 14px;
}

/* Styling for single select */
.single-select {
  /* Add specific styles if needed */
}

/* Styling for multi-select */
.multi-select {
}

/* Styling for searchable select */
.searchable-select {
  position: relative;
}

.searchable-select ul {
  list-style: none;
  padding: 0;
  margin: 0;
  border: 1px solid var(--main-color);
  border-radius: 5px;
  position: absolute;
  top: 100%;
  left: 0;
  background-color: #fff;
  z-index: 1;
  display: none;
  width: 50%;
}

.searchable-select li {
  padding-left: 10px;
  padding-top: 5px;
  padding-bottom: 5px;
}

/* Styling for tag-based select */
.tag-select {
  display: flex;
  flex-wrap: wrap;
  border: 1px solid var(--main-color);
  border-radius: 5px;
  padding: 5px;
}

/* Animation for appearing and fading submenus */
@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
				
			
				
					
// Select elements
const multiSelect = document.getElementById('multiSelect'); // Reference to the multi-select element
const tagSelect = document.querySelector('.tag-select'); // Reference to the tag-based select container

// Function to update the selected options in the tag-based select
function updateTagSelect(selectedOptions) {
  tagSelect.innerHTML = ''; // Clear previous tags

  // Create tag elements for each selected option and append them to the tag-based select container
  selectedOptions.forEach(option => {
    const tag = document.createElement('span');
    tag.textContent = option; // Set the text content to the selected option
    tag.classList.add('tag'); // Apply the 'tag' class to the created tag element
    tagSelect.appendChild(tag); // Add the tag element to the tag-based select container
  });
}

// Event listener for the multi-select
multiSelect.addEventListener('change', () => {
  // Get an array of values from the selected options in the multi-select
  const selectedOptions = Array.from(multiSelect.selectedOptions).map(option => option.value);
  // Update the tag-based select with the newly selected options
  updateTagSelect(selectedOptions);
});

// Event listener for the tag-based select
tagSelect.addEventListener('click', (event) => {
  // Check if the clicked element is a tag
  if (event.target.classList.contains('tag')) {
    const clickedTag = event.target.textContent; // Get the text content of the clicked tag
    const options = Array.from(multiSelect.options); // Get an array of options in the multi-select

    // Toggle selection for the corresponding option in the multi-select based on the clicked tag
    options.forEach(option => {
      if (option.value === clickedTag) {
        option.selected = !option.selected; // Toggle the selection state of the option
      }
    });

    // Update the tag-based select based on the updated selections in the multi-select
    const selectedOptions = Array.from(multiSelect.selectedOptions).map(option => option.value);
    updateTagSelect(selectedOptions);
  }
});

				
			

Searchable Select Demo

				
					
<div class="select-container">
  <!-- Label for the searchable select -->
  <label for="searchableSelect">Searchable Select</label>
  <!-- Container for the searchable select -->
  <div class="searchable-select" role="combobox" aria-expanded="false" aria-haspopup="listbox">
    <!-- Input field for user search with accessibility attributes -->
    <input
      type="text"
      id="searchableSelect"
      aria-autocomplete="list"
      aria-controls="searchableOptions"
      placeholder="Search..."
    />
    <!-- List to display options for the searchable select -->
    <ul id="searchableOptions" class="options-list" role="listbox">
      <!-- Options for the searchable select will be dynamically populated here -->
    </ul>
  </div>
</div>

				
			
				
					
/* Set the brand colors */
:root {
  --main-color: #005e86;
  --secondary-color: #99b4c0;
  --accent-color: #211224;
}

/* Basic styles */
body {
  font-family: 'Barlow', sans-serif;
}

/* Select rows and containers */
.select-row {
  display: flex;
  justify-content: space-between;
  margin-bottom: 20px;
}

.select-container {
  width: 45%;
  position: relative;
}

/* Select styling */
select, input[type="text"] {
  width: 50%;
  padding: 8px;
  border: 1px solid var(--main-color);
  border-radius: 5px;
  font-family: inherit;
  font-size: 14px;
}

/* Styling for single select */
.single-select {
  /* Add specific styles if needed */
}

/* Styling for multi-select */
.multi-select {
  /* Add specific styles if needed */
}

/* Styling for searchable select */
.searchable-select {
  position: relative;
}

.searchable-select ul {
  list-style: none;
  padding: 0;
  margin: 0;
  border: 1px solid var(--main-color);
  border-radius: 5px;
  position: absolute;
  top: 100%;
  left: 0;
  background-color: #fff;
  z-index: 1;
  display: none;
  width: 50%;
}

.searchable-select li {
  padding-left: 10px;
  padding-top: 5px;
  padding-bottom: 5px;
}

/* Styling for tag-based select */
.tag-select {
  display: flex;
  flex-wrap: wrap;
  border: 1px solid var(--main-color);
  border-radius: 5px;
  padding: 5px;
}

/* Animation for appearing and fading submenus */
@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
				
			
				
					
// Sample array of options for the searchable select
const allOptions = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape'];

// Function to populate options in the searchable select based on user input
function populateOptions(searchText) {
  const filteredOptions = allOptions.filter(option => option.toLowerCase().includes(searchText.toLowerCase()));
  const optionsList = document.getElementById('searchableOptions');
  optionsList.innerHTML = ''; // Clear previous options

  if (filteredOptions.length > 0) {
    filteredOptions.forEach(option => {
      const li = document.createElement('li');
      li.textContent = option;
      li.setAttribute('role', 'option');
      li.setAttribute('tabindex', '0'); // Make options focusable
      li.addEventListener('click', () => {
        searchableInput.value = option; // Set input value on click
        optionsList.style.display = 'none'; // Hide options after selection
      });
      optionsList.appendChild(li);
    });
    optionsList.style.display = 'block'; // Show the options
  } else {
    optionsList.style.display = 'none'; // Hide the options if no matches
  }
}

// Select elements
const searchableInput = document.getElementById('searchableSelect');
const optionsList = document.getElementById('searchableOptions');

// Event listeners
searchableInput.addEventListener('input', (event) => {
  const searchText = event.target.value;
  populateOptions(searchText);
});

// Show options dropdown on focus or click
searchableInput.addEventListener('focus', () => {
  const searchText = searchableInput.value;
  populateOptions(searchText);
});

searchableInput.addEventListener('click', () => {
  const searchText = searchableInput.value;
  populateOptions(searchText);
});

// Handle option selection on keyboard navigation
optionsList.addEventListener('keydown', (event) => {
  if (event.key === 'Enter' || event.key === ' ') {
    event.preventDefault();
    const selectedOption = event.target.textContent;
    searchableInput.value = selectedOption; // Set input value on selection
    optionsList.style.display = 'none'; // Hide options after selection
  }
});

// Close the options list if user clicks outside
document.addEventListener('click', (event) => {
  if (!event.target.closest('.searchable-select')) {
    optionsList.style.display = 'none';
  }
}); 
				
			

Tag/Chip Select

				
					
<div class="select-container">
  <!-- Label for the tag-based select -->
  <label for="tagSelect">Tag-based Select</label>
  <!-- Input field for displaying selected tags -->
  <input type="text" id="tagInput" readonly>
  <!-- Container for the tag-based select -->
  <div class="tag-select" role="listbox">
    <!-- Container to display selected tags as 'chips' -->
    <div class="tag-container" id="tagContainer"></div>
  </div>
</div>

				
			
				
					
/* Set the brand colors */
:root {
  --main-color: #005e86;
  --secondary-color: #99b4c0;
  --accent-color: #211224;
}

/* Basic styles */
body {
  font-family: 'Barlow', sans-serif;
}

/* Select container */
.select-container {
  width: 200px; /* Adjust as needed */
}

/* Label style */
.select-container label {
  display: block;
  margin-bottom: 5px;
}

/* Tag-select styles */
.tag-select {
  position: relative;
}

#tagInput {
  width: calc(100% - 2px);
  padding: 8px;
  border: 1px solid var(--main-color);
  border-radius: 5px;
  font-family: inherit;
  font-size: 14px;
  margin-bottom: 5px;
}

/* Ensure the list items display vertically */
.tag-select .tag {
  display: block; /* Make tags display vertically */
  padding: 8px;
  cursor: pointer;
}

.tag-select .tag:hover {
  background-color: #f0f0f0;
}
				
			
				
					
document.addEventListener('DOMContentLoaded', () => {
  const allOptionsForTags = ['Tag1', 'Tag2', 'Tag3', 'Tag4', 'Tag5', 'Tag6', 'Tag7'];
  const tagInput = document.getElementById('tagInput');
  const tagContainer = document.getElementById('tagContainer');

  const selectedTags = new Set(); // To store selected tags

  // Function to populate options in the tag-based select
  function populateOptionsForTags() {
    tagContainer.innerHTML = ''; // Clear previous tags
    allOptionsForTags.forEach(option => {
      const tag = document.createElement('div');
      tag.textContent = option;
      tag.classList.add('tag');
      tag.setAttribute('tabindex', '0'); // Make tags focusable
      tagContainer.appendChild(tag);
    });
  }

  // Event listener to display the tag dropdown when input is focused/clicked
  tagInput.addEventListener('focus', () => {
    populateOptionsForTags();
    tagContainer.style.display = 'block';
  });

  // Event listener to hide the tag dropdown when input is blurred
  tagInput.addEventListener('blur', (event) => {
    // Delay hiding the dropdown to allow click events to be detected on tags
    setTimeout(() => {
      if (!tagContainer.contains(event.relatedTarget)) {
        tagContainer.style.display = 'none';
      }
    }, 100); // Adjust the delay as needed
  });

  // Event listener for selecting a tag from the dropdown using click or Enter key
  tagContainer.addEventListener('click', (event) => {
    if (event.target.classList.contains('tag')) {
      const clickedTag = event.target.textContent;
      if (!selectedTags.has(clickedTag)) {
        selectedTags.add(clickedTag);
        tagInput.value += `${clickedTag} `;
      } else {
        selectedTags.delete(clickedTag);
        tagInput.value = tagInput.value.replace(clickedTag + ' ', '');
      }
      tagInput.focus(); // Return focus to the input field
    }
  });

  // Event listener for keyboard navigation within the tag dropdown
  tagContainer.addEventListener('keydown', (event) => {
    const focusedTag = document.activeElement;

    if (event.key === 'Enter' && focusedTag.classList.contains('tag')) {
      const clickedTag = focusedTag.textContent;
      if (!selectedTags.has(clickedTag)) {
        selectedTags.add(clickedTag);
        tagInput.value += `${clickedTag} `;
        tagInput.focus(); // Return focus to the input field
      } else {
        selectedTags.delete(clickedTag);
        tagInput.value = tagInput.value.replace(clickedTag + ' ', '');
      }
    }
  });

  // Event listener for adding tags via Enter key
  tagInput.addEventListener('keydown', function (event) {
    if (event.key === 'Enter' || event.keyCode === 13) {
      event.preventDefault();
      const value = this.value.trim();

      if (value !== '') {
        selectedTags.add(value);
        tagInput.value += `${value} `;
        this.value = ''; // Clear input after adding the tag
        tagInput.focus(); // Return focus to the input field
      }
    }
  });
});
				
			

Why use a select element?

Select elements are fundamental components in web development that offer users a structured and intuitive way to make choices or selections from a list of options. These elements provide a dropdown menu displaying multiple choices, allowing users to pick one or more options based on their needs. From an accessibility perspective, select elements offer inherent benefits by enabling keyboard navigation, ensuring compatibility with screen readers, and supporting various assistive technologies. They contribute to a more inclusive user experience by allowing users with motor impairments or visual disabilities to interact with the interface effectively. Select elements also ensure consistency in user interaction patterns, facilitating a familiar and predictable method for users to navigate and make selections across different web applications and devices. Overall, the proper implementation of select elements aligns with accessibility standards, enhancing usability and accessibility for all users across diverse browsing environments.

What are some accessibility concerns?

  1. Keyboard Accessibility:
    • Concern: Keyboard-only users might encounter difficulties navigating and selecting options within the dropdown.
    • Mitigation: Ensure the select element and its options are accessible via keyboard navigation (Tab/Arrow keys) without relying solely on mouse interaction.
  2. Screen Reader Compatibility:
    • Concern: Screen reader users may struggle to perceive or interact with the select element’s options.
    • Mitigation: Use proper semantic markup (e.g., <select>, <option>) and associated labels (using <label> or aria-labelledby) for screen readers to interpret and convey the select’s purpose and options accurately.
  3. Visual and Cognitive Accessibility:
    • Concern: Users with visual impairments or cognitive disabilities might find it challenging to perceive or comprehend the options.
    • Mitigation: Provide sufficient contrast between the select element and its options to ensure visibility. Utilize clear labels or additional visual cues (like borders or icons) to aid comprehension.
  4. Mobile and Touch Accessibility:
    • Concern: Select elements might be challenging to interact with on touch devices or smaller screens.
    • Mitigation: Optimize the select element’s design for touch devices, ensuring sufficient touch target sizes and intuitive interactions for users with limited dexterity.
  5. ARIA Attributes:
    • Concern: Proper usage of ARIA attributes to enhance functionality and convey the select element’s state to assistive technologies.
    • Mitigation: Implement appropriate ARIA attributes (aria-expanded, aria-selected, etc.) to enhance the select element’s functionality and convey its state to assistive technologies.
  6. Error Handling and Validation:
    • Concern: Clear error messages and validation cues for users encountering issues with selecting options or during submission.
    • Mitigation: Ensure clear error messages and validation cues for users if there are issues with selecting options or if errors occur during submission.
Tested using
Chrome
with NVDA
Firefox
with NVDA
  • W3C SVG
    1.3.1
    Info and Relationships ( level A ) :
    Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
  • W3C SVG
    2.1.1
    Keyboard ( level A ) :
    All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints.
  • W3C SVG
    2.1.2
    No Keyboard Trap ( level A ) :
    If keyboard focus can be moved to a component of the page using a keyboard interface, then focus can be moved away from that component using only a keyboard interface, and, if it requires more than unmodified arrow or tab keys or other standard exit methods, the user is advised of the method for moving focus away.
  • W3C SVG
    2.4.3
    Focus Order ( level A ) :
    If a Web page can be navigated sequentially and the navigation sequences affect meaning or operation, focusable components receive focus in an order that preserves meaning and operability.
  • W3C SVG
    4.1.2
    Name, Role, Value ( level A ) :
    For all user interface components (including but not limited to: form elements, links and components generated by scripts), the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to user agents, including assistive technologies.