Select Components
Standard Select Demo
/* 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
/* 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
/* 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
/* 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?
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
- 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.
- 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.
- 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.
- 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.