JSFiddle - React, Tailwind, and code Playground
by Imri Paloja
HTML
<select id="native-select" name="country" hidden>
<option value="">Select country</option>
<option value="us">USA</option>
<option value="ca">Canada</option>
<option value="uk">United Kingdom</option>
<option value="fr">France</option>
</select>
<div class="select" id="custom-select" tabindex="0">
<div class="select-trigger">Select country</div>
<div class="select-dropdown">
<input type="text" class="select-search" placeholder="Search..." />
<ul class="select-options"></ul>
</div>
</div>
CSS
.select {
width: 260px;
position: relative;
font-family: system-ui, sans-serif;
}
.select-trigger {
padding: 10px 12px;
border: 1px solid #ccc;
border-radius: 6px;
cursor: pointer;
background: white;
}
.select.open .select-trigger {
border-color: #4f46e5;
}
.select-dropdown {
display: none;
position: absolute;
width: 100%;
margin-top: 4px;
background: white;
border: 1px solid #ccc;
border-radius: 6px;
max-height: 220px;
overflow: auto;
z-index: 10;
}
.select.open .select-dropdown {
display: block;
}
.select-search {
width: 100%;
padding: 8px;
border: none;
border-bottom: 1px solid #eee;
outline: none;
}
.select-options li {
padding: 8px 12px;
cursor: pointer;
}
.select-options li:hover,
.select-options li.active {
background: #eef2ff;
}
JavaScript
const nativeSelect = document.getElementById('native-select');
const custom = document.getElementById('custom-select');
const trigger = custom.querySelector('.select-trigger');
const dropdown = custom.querySelector('.select-dropdown');
const search = custom.querySelector('.select-search');
const list = custom.querySelector('.select-options');
const options = [...nativeSelect.options].slice(1);
function render(filter = '') {
list.innerHTML = '';
options
.filter((o) => o.text.toLowerCase().includes(filter.toLowerCase()))
.forEach((o) => {
const li = document.createElement('li');
li.textContent = o.text;
li.onclick = () => selectOption(o);
list.appendChild(li);
});
}
function selectOption(option) {
nativeSelect.value = option.value;
trigger.textContent = option.text;
custom.classList.remove('open');
}
trigger.onclick = () => {
custom.classList.toggle('open');
search.focus();
};
search.oninput = (e) => render(e.target.value);
document.addEventListener('click', (e) => {
if (!custom.contains(e.target)) custom.classList.remove('open');
});
render();