You know that dropdown you've been tweaking for 3 hours, trying to get the focus management right? The one where pressing Escape sometimes works and sometimes doesn't? Headless UI's Menu component handles all that keyboard navigation bullshit for you. You just worry about making it look good.
The Problem It Solves
Ever tried overriding Material-UI's button styles to match your design system? Spent 2 days fighting with Bootstrap's modal z-index? This is exactly why Headless UI exists.
Traditional libraries like Material-UI, Ant Design, and Chakra UI give you pretty components that look exactly like everyone else's app. Headless UI gives you the behavior without the baggage. No more CSS specificity wars. No more !important
everywhere. No more explaining to your PM why the "simple" dropdown took 3 days when Material-UI's z-index system conflicts with your layout.
What You Get (Besides a Headache)
Every Headless UI component handles the shit that you'd probably mess up:
- Keyboard navigation that actually works - Tab, Enter, Escape do what users expect. I've tested this shit with screen readers, it's solid.
- Focus trapping in modals - No more users tabbing into the background while your modal is open. This alone saves hours of debugging.
- Screen reader support - ARIA labels, roles, and states that actually make sense to assistive technology
- Mobile touch handling - Touch events that don't break your keyboard navigation
- State management - Open/closed, selected, disabled states managed properly
React gets all the new stuff first. Vue support is stuck on v1.x because Tailwind Labs clearly doesn't give a shit about Vue users - you get updates whenever they feel like porting them over. The form components that shipped in React v2.0 took forever to reach Vue, and some features are still missing.
React 17.x breaks the Transition component with Concurrent Mode. You'll get "Cannot read properties of null" or "ReferenceError: process is not defined" errors. Upgrade to React 18+ or disable Concurrent Mode. Learned that after debugging for 3 hours wondering why transitions randomly stopped working.
The Bundle Size Reality Check
Headless UI React is like 50KB. Material-UI? Christ, it's over 300KB. Ant Design is even worse. But here's the catch everyone forgets to mention: you're trading bundle size for development time.
Yes, your JavaScript bundle is smaller. But you're about to write a ton of CSS. Pick your poison:
- Big bundle, components work out of the box
- Small bundle, plan on 2-3x longer styling time
Accessibility: The Good and the Bad
The accessibility stuff is genuinely excellent. Focus management, keyboard navigation, screen reader support - it's all there and it actually works. I've tested it with NVDA, JAWS, and VoiceOver.
But accessibility isn't just JavaScript. You can still fuck it up with bad CSS. Hide something with display: none
that should be visibility: hidden
? Congratulations, you just broke screen reader navigation. Read WebAIM's guide to CSS and accessibility and MDN's accessibility best practices. The components give you the foundation; don't screw up the styling layer with CSS that breaks accessibility.