0
0
Tailwindmarkup~5 mins

Component library patterns (Headless UI) in Tailwind

Choose your learning style9 modes available
Introduction

Headless UI helps you build components without styling so you can add your own look easily. It gives you the structure and behavior, but you control the design.

When you want accessible components but want full control over how they look.
When you need reusable UI parts like menus, modals, or tabs without built-in styles.
When you want to combine Tailwind CSS with interactive components easily.
When you want to avoid writing complex JavaScript for common UI patterns.
When you want to keep your design consistent but flexible across your app.
Syntax
Tailwind
import { Menu } from '@headlessui/react'

<Menu>
  <Menu.Button>Options</Menu.Button>
  <Menu.Items>
    <Menu.Item>
      {({ active }) => (
        <a className={`${active ? 'bg-blue-500 text-white' : 'text-gray-900'}`} href="#">
          Account settings
        </a>
      )}
    </Menu.Item>
  </Menu.Items>
</Menu>
Headless UI components use a render prop pattern to give you state like 'active' to style items.
You import components from '@headlessui/react' and wrap your elements to get accessibility and behavior.
Examples
This example shows a modal dialog with accessible roles and overlay. You control when it opens and closes.
Tailwind
import { Dialog } from '@headlessui/react'

<Dialog open={isOpen} onClose={setIsOpen}>
  <Dialog.Overlay />
  <Dialog.Title>Deactivate account</Dialog.Title>
  <Dialog.Description>
    This will permanently deactivate your account
  </Dialog.Description>
  <button onClick={() => setIsOpen(false)}>Close</button>
</Dialog>
This example creates tabs with keyboard navigation and focus management built-in.
Tailwind
import { Tab } from '@headlessui/react'

<Tab.Group>
  <Tab.List>
    <Tab>First</Tab>
    <Tab>Second</Tab>
  </Tab.List>
  <Tab.Panels>
    <Tab.Panel>Content for first tab</Tab.Panel>
    <Tab.Panel>Content for second tab</Tab.Panel>
  </Tab.Panels>
</Tab.Group>
Sample Program

This example shows a simple dropdown menu using Headless UI patterns with Tailwind CSS styling. The menu button toggles the menu items. The menu is keyboard accessible and closes when clicking outside.

Tailwind
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Headless UI Menu Example</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script type="module">
    window.addEventListener('DOMContentLoaded', () => {
      const menuButton = document.getElementById('menu-button')
      const menuItems = document.getElementById('menu-items')

      menuButton.addEventListener('click', (event) => {
        event.stopPropagation();
        const expanded = menuButton.getAttribute('aria-expanded') === 'true'
        menuButton.setAttribute('aria-expanded', String(!expanded))
        menuItems.classList.toggle('hidden')
      })

      // Close menu when clicking outside
      document.addEventListener('click', (event) => {
        if (!menuButton.contains(event.target) && !menuItems.contains(event.target)) {
          menuButton.setAttribute('aria-expanded', 'false')
          menuItems.classList.add('hidden')
        }
      })
    })
  </script>
</head>
<body class="flex items-center justify-center min-h-screen bg-gray-100">
  <div class="relative inline-block text-left">
    <button id="menu-button" aria-haspopup="true" aria-expanded="false" class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm 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-offset-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" aria-hidden="true">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
      </svg>
    </button>
    <div id="menu-items" 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" role="menu" aria-orientation="vertical" aria-labelledby="menu-button" tabindex="-1">
      <div class="py-1" role="none">
        <a href="#" class="text-gray-700 block px-4 py-2 text-sm hover:bg-indigo-600 hover:text-white" role="menuitem" tabindex="-1">Account settings</a>
        <a href="#" class="text-gray-700 block px-4 py-2 text-sm hover:bg-indigo-600 hover:text-white" role="menuitem" tabindex="-1">Support</a>
        <a href="#" class="text-gray-700 block px-4 py-2 text-sm hover:bg-indigo-600 hover:text-white" role="menuitem" tabindex="-1">License</a>
      </div>
    </div>
  </div>
</body>
</html>
OutputSuccess
Important Notes

Headless UI components provide accessibility features like keyboard navigation and ARIA roles automatically.

You style the components yourself using Tailwind CSS or any other method, so your design stays consistent.

Headless UI works well with React, but you can implement similar patterns manually in plain HTML/JS as shown.

Summary

Headless UI gives you the behavior and accessibility of components without styling.

You add your own styles using Tailwind CSS or other CSS tools.

This helps build flexible, accessible, and reusable UI parts easily.