Dropdown menus are essential in modern UIs for navigation, actions, and settings. But building them accessibly—with keyboard support, ARIA attributes, and responsive styling—can be challenging. Using Tailwind CSS and vanilla JavaScript, we can create dropdown components that are both user-friendly and scalable.
Why Focus on Accessibility?
- Ensures keyboard navigation and screen-reader usability
- Builds trust with all users, including those relying on assistive tech
- Meets WCAG guidelines without external dependencies
HTML Structure & Tailwind Styling
<div class="relative inline-block text-left">
<button id="dropdownBtn" aria-expanded="false" aria-haspopup="true"
class="inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500">
Options
<svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path d="M19 9l-7 7-7-7" />
</svg>
</button>
<div id="dropdownMenu" role="menu" aria-labelledby="dropdownBtn"
class="hidden origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none">
<div class="py-1" role="none">
<a href="#profile" role="menuitem" tabindex="-1" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
Profile
</a>
<a href="#settings" role="menuitem" tabindex="-1" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
Settings
</a>
<a href="#logout" role="menuitem" tabindex="-1" class="block px-4 py-2 text-sm text-red-700 hover:bg-red-100">
Sign out
</a>
</div>
</div>
</div>
- Uses semantic roles (
menu
,menuitem
) and ARIA attributes - Styled with Tailwind:
rounded-md
,shadow-lg
,ring
, and focus utilities
JavaScript for Interaction & Accessibility
const btn = document.getElementById('dropdownBtn');
const menu = document.getElementById('dropdownMenu');
let open = false;
btn.addEventListener('click', () => {
open = !open;
menu.classList.toggle('hidden', !open);
btn.setAttribute('aria-expanded', open);
if (open) {
const first = menu.querySelector('[role="menuitem"]');
first.focus();
}
});
document.addEventListener('keydown', (e) => {
if (!open) return;
const items = Array.from(menu.querySelectorAll('[role="menuitem"]'));
const currentIndex = items.indexOf(document.activeElement);
if (e.key === 'ArrowDown') {
e.preventDefault();
items[(currentIndex + 1) % items.length].focus();
} else if (e.key === 'ArrowUp') {
e.preventDefault();
items[(currentIndex - 1 + items.length) % items.length].focus();
} else if (e.key === 'Escape') {
open = false;
menu.classList.add('hidden');
btn.setAttribute('aria-expanded', 'false');
btn.focus();
}
});
document.addEventListener('click', (e) => {
if (open && !btn.contains(e.target) && !menu.contains(e.target)) {
open = false;
menu.classList.add('hidden');
btn.setAttribute('aria-expanded', 'false');
}
});
Responsive & Dark Mode Enhancements
- Style background and text colors with
dark:bg-gray-800 dark:text-gray-200
- Ensure
focus:ring
andhover
states are visible in both themes - Use mobile-friendly
w-full sm:w-56
for adaptive sizing
Get My 37‑Page PDF Guide
If you're building reusable, accessible components across apps, Mastering Tailwind at Scale: Architecture, Patterns & Performance helps you:
- Structure utilities and theming at scale
- Build ARIA-compliant, keyboard-accessible UI modules
- Optimize CSS bundle size and performance
- Apply design tokens and component architecture
- Access practical patterns with diagrams, code snippets, and checklist-style guides
This 37‑page guide is available now on Gumroad for only $10, ready to download instantly.
👉 Get your copy here:
Mastering Tailwind at Scale: Architecture, Patterns & Performance
Craft dropdowns that are usable for all—using Tailwind and inclusive JavaScript patterns.
Top comments (0)