4 Tailwind2 with JSPublished 2026-10-04Free · no sign-up
Six select patterns in Tailwind: a native select with a custom chevron, a dark select with option groups, a fully custom listbox, a compact sort pill, a checkbox multi-select in a disclosure and a type-to-filter datalist.
A native select styled with Tailwind utilities: appearance-none, padding for the arrow and an SVG chevron as an arbitrary background value. It keeps the platform option list and mobile picker, which is usually the best choice.
A dark native select with optgroups for organising options, using the scheme-dark arbitrary property so the browser draws the opened menu in dark colours too. Focus uses a coloured ring that is easy to see on the dark field.
A fully custom select-only combobox styled with Tailwind, for cases where the options need rich content. It supports arrow keys, Enter, Escape and clicking, marks the selected option with aria-selected, and shows a tick with aria-selected: utilities.
const b = document.getElementById('twlb-b'), l = document.getElementById('twlb-o'), os = [...l.children];
let a = 0;
os.forEach((o, i) => o.id = 'twlbo' + i);
function open(v) { l.hidden = !v; b.setAttribute('aria-expanded', String(v)); if (v) mark(os.findIndex(o => o.getAttribute('aria-selected') === 'true')); else b.removeAttribute('aria-activedescendant'); }
function mark(i) { a = (i + os.length) % os.length; os.forEach((o, k) => o.classList.toggle('act', k === a)); b.setAttribute('aria-activedescendant', os[a].id); }
function pick(i) { os.forEach((o, k) => o.setAttribute('aria-selected', String(k === i))); b.textContent = os[i].textContent; open(false); }
b.addEventListener('click', () => open(l.hidden));
b.addEventListener('keydown', e => {
if (l.hidden) { if (['ArrowDown', 'Enter', ' '].includes(e.key)) { e.preventDefault(); open(true); } return; }
if (e.key === 'ArrowDown') { e.preventDefault(); mark(a + 1); } else if (e.key === 'ArrowUp') { e.preventDefault(); mark(a - 1); }
else if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); pick(a); } else if (e.key === 'Escape') open(false);
});
os.forEach((o, i) => o.addEventListener('click', () => { pick(i); b.focus(); }));
document.addEventListener('click', e => { if (!e.target.closest('#twlb')) open(false); });
04. Tailwind Inline Sort Select
TailwindCompact
A compact sort control for a product toolbar: visible text reads Sort: Newest, and a transparent native select covers the whole pill so it opens the system menu. focus-within: puts the focus ring on the visible pill.
A multi-select built from a details disclosure holding a list of checkboxes, with the summary showing how many are chosen. It needs only a few lines of JavaScript for the count, and every checkbox keeps its native keyboard behaviour.
const ms = [...document.querySelectorAll('.twm')];
ms.forEach(m => m.addEventListener('change', () => { const n = ms.filter(x => x.checked).length; document.getElementById('twmc').textContent = n ? n + ' selected' : 'None'; }));
06. Tailwind Searchable Input
TailwindDatalist
A type-to-filter field powered by an HTML datalist, styled with Tailwind. The browser draws the suggestion menu, people can still enter their own value, and no JavaScript or library is needed for a long list of options.
appearance-none plus an arbitrary background-image chevron lets a native select match your design while keeping the system picker on phones, which is the most accessible option.
Dark selects
Setting [color-scheme:dark] on a wrapper tells the browser to draw the opened option list in dark colours, so it matches a dark field.
Custom listbox
The listbox demo follows the ARIA select-only combobox pattern and styles the selected option with aria-selected: utilities, so the look always follows the accessible state.
Multi-select without a library
A details disclosure holding checkboxes gives a dependable multi-select; the summary shows the selected count, updated by a few lines of script.
Frequently asked questions
Do I need the Tailwind forms plugin?
No. These style the elements directly with utilities.
Which demos use JavaScript?
The listbox and the multi-select count; the sort pill uses one inline handler.