JSFiddle - React, Tailwind, and code Playground
by Ravindra Athreya
HTML
<div class="custom-select">
<div class="select-box">
<input type="text" class="select-input" placeholder="Select options" readonly>
<div class="dropdown">
<ul class="dropdown-list">
<!-- Optgroup 1 -->
<li class="optgroup">
<div class="optgroup-header">
<label>
<input type="checkbox" class="optgroup-checkbox">
<span>Fruits</span>
</label>
<span class="toggle">[+]</span>
</div>
<ul class="optgroup-content">
<li><label><input type="checkbox" class="option-checkbox"> Apple</label></li>
<li><label><input type="checkbox" class="option-checkbox"> Banana</label></li>
<li><label><input type="checkbox" class="option-checkbox"> Cherry</label></li>
</ul>
</li>
<!-- Optgroup 2 -->
<li class="optgroup">
<div class="optgroup-header">
<label>
<input type="checkbox" class="optgroup-checkbox">
<span>Vegetables</span>
</label>
<span class="toggle">[+]</span>
</div>
<ul class="optgroup-content">
<li><label><input type="checkbox" class="option-checkbox"> Carrot</label></li>
<li><label><input type="checkbox" class="option-checkbox"> Broccoli</label></li>
<li><label><input type="checkbox" class="option-checkbox"> Spinach</label></li>
</ul>
</li>
</ul>
...
CSS
/* Custom Select Styling */
.custom-select {
width: 300px;
position: relative;
}
.select-box {
border: 1px solid #ccc;
border-radius: 5px;
padding: 10px;
cursor: pointer;
position: relative;
}
.select-input {
width: 100%;
border: none;
outline: none;
background: none;
}
.dropdown {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
border: 1px solid #ccc;
background-color: white;
max-height: 200px;
overflow-y: auto;
z-index: 1;
}
.dropdown-list {
list-style: none;
padding: 0;
margin: 0;
}
.dropdown-list li {
padding: 8px 10px;
}
.optgroup {
font-weight: bold;
}
.optgroup-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.optgroup-checkbox {
margin-right: 8px;
}
.option-checkbox {
margin-right: 8px;
}
.optgroup-content {
display: none;
padding-left: 20px;
}
/* Toggle to expand/collapse optgroup */
.toggle {
cursor: pointer;
}
/* Show dropdown on select box click */
.select-box.open .dropdown {
display: block;
}
/* Expanded optgroup */
.optgroup-expanded .optgroup-content {
display: block;
}
JavaScript
document.addEventListener("DOMContentLoaded", function () {
const selectBox = document.querySelector(".select-box");
const inputBox = document.querySelector(".select-input");
const dropdown = document.querySelector(".dropdown");
const optgroupCheckboxes = document.querySelectorAll(".optgroup-checkbox");
const optionCheckboxes = document.querySelectorAll(".option-checkbox");
const toggleButtons = document.querySelectorAll(".toggle");
// Toggle dropdown visibility on select box click
selectBox.addEventListener("click", function () {
selectBox.classList.toggle("open");
});
// Handle optgroup checkbox click (Select/Deselect all items within group)
optgroupCheckboxes.forEach(optgroupCheckbox => {
optgroupCheckbox.addEventListener("change", function () {
const group = optgroupCheckbox.closest(".optgroup").querySelectorAll(".option-checkbox");
group.forEach(optionCheckbox => {
optionCheckbox.checked = optgroupCheckbox.checked;
});
updateSelectionText();
});
});
// Handle individual option checkbox click
optionCheckboxes.forEach(optionCheckbox => {
optionCheckbox.addEventListener("change", updateSelectionText);
});
// Handle expand/collapse of optgroups
toggleButtons.forEach(toggleButton => {
toggleButton.addEventListener("click", function () {
const optgroup = toggleButton.closest(".optgroup");
const content = optgroup.querySelector(".optgroup-content");
const isExpanded = optgroup.classList.toggle("optgroup-expanded");
toggleButton.textContent = isExpanded ? "[-]" : "[+]";
});
});
// Update the input text based on selected options
function updateSelectionText() {
const selectedOptions = [];
optionCheckboxes.forEach(option => {
if (option.checked) {
...