Completely unstyled, fully accessible UI components, designed to integrate beautifully with Tailwind CSS.

  • By Tailwind Labs
  • Last update: Sep 27, 2022
  • Comments: 16

Headless UI

A set of completely unstyled, fully accessible UI components, designed to integrate beautifully with Tailwind CSS.


Documentation

For full documentation, visit headlessui.dev.

Packages

Name Version Downloads
@headlessui/react npm version npm downloads
@headlessui/vue npm version npm downloads

Community

For help, discussion about best practices, or any other conversation that would benefit from being searchable:

Discuss Headless UI on GitHub

For casual chit-chat with others using the library:

Join the Tailwind CSS Discord Server

Github

https://github.com/tailwindlabs/headlessui

Comments(16)

  • 1

    [Bug]: Uncaught RangeError: Maximum call stack size exceeded. focusElement of Modal

    What package within Headless UI are you using?

    @headlessui/react

    What version of that package are you using?

    1.4.1

    What browser are you using?

    chrome

    Reproduction repository

    Not now.

    Describe your issue

    while we create Modal multiple (2+) it will throw me

    focus-management.esm.js?d1e3:99 Uncaught RangeError: Maximum call stack size exceeded.
        at focusElement (focus-management.esm.js?d1e3:99)
        at eval (use-focus-trap.esm.js?25af:110)
        at handler (use-window-event.esm.js?b5e3:8)
        at focusElement (focus-management.esm.js?d1e3:99)
        at eval (use-focus-trap.esm.js?25af:110)
        at handler (use-window-event.esm.js?b5e3:8)
        at focusElement (focus-management.esm.js?d1e3:99)
        at eval (use-focus-trap.esm.js?25af:110)
        at handler (use-window-event.esm.js?b5e3:8)
        at focusElement (focus-management.esm.js?d1e3:99)
        at eval (use-focus-trap.esm.js?25af:110)
        at handler (use-window-event.esm.js?b5e3:8)
        at focusElement (focus-management.esm.js?d1e3:99)
        at eval (use-focus-trap.esm.js?25af:110)
        at handler (use-window-event.esm.js?b5e3:8)
        at focusElement (focus-management.esm.js?d1e3:99)
        at eval (use-focus-trap.esm.js?25af:110)
        at handler (use-window-event.esm.js?b5e3:8)
        at focusElement (focus-management.esm.js?d1e3:99)
        at eval (use-focus-trap.esm.js?25af:110)
    

    Screenshot here

    BTW, can Modal need to provider flag props to disabled focusElement feature, in most case we don't need this, i think.

  • 2

    Multi-Listbox

    Hey there,

    Just a first attempt/POC for a multi-select Listbox (see #181).

    React-only at this stage.

    https://user-images.githubusercontent.com/690667/123712986-af5edb00-d873-11eb-8085-10dbf11b9fc5.mov

    It involves a few changes, mostly:

    • Tracking the value in theListbox state, to be able to detect selected options while the Listbox is open
    • Checking here and there if value is an array
    • Focus handling

    All in all, it seems to work ok, the only thing I can't get around is that when you use clickable items within Listbox.button (ex: badges with a remove action), the button gain focus on click, and it kind of messes things up.

    I've added a basic test case - just a start.

    Let me know if you'd like me to explore / improve this further, or if you prefer to handle this yourself :)

  • 3

    HeadlessUI is not working with Nuxt 3

    What package within Headless UI are you using?

    @headlessui/vue

    What version of that package are you using?

    "devDependencies": {
        "autoprefixer": "^10.4.0",
        "nuxt3": "latest",
        "postcss": "^8.4.4",
        "tailwindcss": "^2.2.19"
      },
      "dependencies": {
        "@headlessui/vue": "^1.4.2",
        "@heroicons/vue": "^1.0.5",
        "@tailwindcss/forms": "^0.3.4"
      }
    

    Describe your issue

    It works fine with development but when I build nuxt (nuxi build) and start (yarn start) it gives error. I've tried to import headless ui component from @headlessui/vue/dist/index.js instead of @headlessui/vue but its still same.

    TypeError: Cannot read property 'buttonRef' of undefined
        at setup (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:2622:15)
        at callWithErrorHandling (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:7158:22)
        at setupStatefulComponent (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:6874:29)
        at setupComponent (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:6855:11)
        at renderComponentVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9757:17)
        at renderVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9863:22)
        at renderVNodeChildren (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9878:9)
        at renderElementVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9929:17)
        at renderVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9860:17)
        at renderVNodeChildren (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9878:9)
    [Vue warn]: inject() can only be used inside setup() or functional components.
    TypeError: Cannot read property 'menuState' of undefined
        at Proxy.render$1 (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:2522:17)
        at renderComponentRoot (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:2015:44)
        at renderComponentSubTree (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9828:51)
        at renderComponentVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9773:16)
        at renderVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9863:22)
        at renderVNodeChildren (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9878:9)
        at renderElementVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9929:17)
        at renderVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9860:17)
        at renderVNodeChildren (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9878:9)
        at renderElementVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9929:17)
    [Vue warn]: inject() can only be used inside setup() or functional components.
    [Vue warn]: Unhandled error during execution of watcher callback
    TypeError: Cannot read property 'itemsRef' of undefined
        at ReactiveEffect.fn (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:2685:24)
        at ReactiveEffect.run (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\reactivity\dist\reactivity.cjs.js:164:29)
        at ComputedRefImpl.get value [as value] (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\reactivity\dist\reactivity.cjs.js:1075:39)
        at D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:2336:26
        at callWithErrorHandling (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:6615:22)
        at callWithAsyncErrorHandling (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:6624:21)
        at ReactiveEffect.getter [as fn] (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:6970:24)
        at ReactiveEffect.run (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\reactivity\dist\reactivity.cjs.js:164:29)
        at doWatch (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:7078:16)
        at Object.watchEffect (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:6890:12)
    [Vue warn]: inject() can only be used inside setup() or functional components.
    TypeError: Cannot read property 'menuState' of undefined
        at Proxy.render$1 (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:2656:17)
        at renderComponentRoot (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:2015:44)
        at renderComponentSubTree (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9828:51)
        at renderComponentVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9773:16)
        at renderVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9863:22)
        at renderComponentSubTree (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9828:13)
        at renderComponentVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9773:16)
        at renderVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9863:22)
        at renderComponentSubTree (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9780:9)
        at renderComponentVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9773:16)
    
    
  • 4

    [Bug]: Dialog: There are no focusable elements inside the

    What package within Headless UI are you using?

    @headlessui/react

    What version of that package are you using?

    1.0.0

    What browser are you using?

    Chrome

    Reproduction repository

    https://codesandbox.io/s/gallant-butterfly-wnxjb

    Description

    When there is no focusable element inside modal, it fails with error There are no focusable elements inside the <FocusTrap />. I don't know if it's a feature or a bug, but there isn't said in the documentation that Dialog must include at least one focusable element and I totally see a use-case when there are modals without any focusable element. I think it at least should fail with warning instead of fatal error.

    Anyways I would like to thank you for the great job you all are doing with the tailwind ecosystem, we really appreciate your work!

  • 5

    [Bug]: Interacting with third-party components that use portals inside a Dialog closes the Dialog

    What package within Headless UI are you using?

    @headlessui/vue

    What version of that package are you using?

    1.0.0

    What browser are you using?

    Firefox

    Reproduction repository

    https://codesandbox.io/s/pensive-fast-yxokp?file=/src/App.vue

    Describe your issue

    When any component inside a Dialog renders itself elsewhere in the DOM using a Portal/Teleport, clicking in it closes the entire Dialog. The example above uses vue-flatpickr-component to create a date picker inside a modal, but because it renders the actual flatpickr instance somewhere else in the DOM, clicking any date closes the entire modal.

    The docs on this say:

    When a Dialog is rendered, clicking the DialogOverlay will close the Dialog.

    But that isn't exactly the caseβ€”it's not clicking the DialogOverlay specifically that closes the Dialog, but clicking anything that is not a child of the Dialog in the DOM.

    I believe the relevant part of the code is here: https://github.com/tailwindlabs/headlessui/blob/main/packages/%40headlessui-vue/src/components/dialog/dialog.ts#L174-L184

    What do you think about adding a way to disable that global mousedown handler, or adding an option to actually only close the Dialog based on clicks directly on the DialogOverlay component?

  • 6

    Transition not working in NextJs

    It appears like Transition classes are not there initially on any div(<Transition>) Btw I'm using ( tailwindcss(^1.8.4) , styled-components & twin-macro)

    Sample code I'm trying to test on my NextJs WebApp image

  • 7

    [Bug]: Performance issues with Select Custom Dropdown on big lists

    What package within Headless UI are you using?

    @headlessui/react

    What version of that package are you using?

    v1.1.1

    What browser are you using?

    Firefox

    Reproduction repository

    https://github.com/khuang7/headlessui-listbox-issue (yarn install then yarn start)

    Describe your issue

    I am trying to populate a pretty big list (500 elements) into the Simple Custom component found in TailwindUI for my project. The hover behavior when trying to select an option becomes quite slow when you try to move the mouse around on all the options. Also generating the list can sometimes be slow as well.

    My workaround this problem is to replace Listbox.Options and Listbox.Option to ul and li html elements so that I can just call 'hover:' on the li elements which improves performance significantly. But I would prefer to keep using the HeadlessUI instead of HTML because I would lose a lot of the ARIA accessibility features.

    I was wondering if there is a way to deal with the performance issues in the HeadlessUI. I could only pinpoint the issue being related to ListboxOptions and ListboxOption.

  • 8

    Feature: close popover manually

    What package within Headless UI are you using?

    @headlessui/vue

    What version of that package are you using?

    v1.0.0

    What browser are you using?

    Chrome

    Reproduction repository

    Describe your issue

    At the moment it is not possible to manually close the popover. Let's say I want to build an editable table. The editable content should be shown in the popover. When I hit the save button it should also close the popover. This is not possible, because the slots does not expose the function togglePopover.

  • 9

    Dialog throws error if there are no focusable elements

    I get the following error if I create a Dialog with no interactive components (just text): Error: There are no focusable elements inside the <FocusTrap />

  • 10

    Control whether Menu closes on Menu.Item click

    Hi there! I have a use case for the Menu component where I don't necessarily want the Menu to close when I click on a Menu.Item. Or, in other words, I would like to be able to control when the menu closes in some way.

  • 11

    Regression: No transitions on open dialog [v1.6.5]

    What package within Headless UI are you using?

    @headlessui/vue

    What version of that package are you using?

    1.6.5

    What browser are you using?

    Chrome

    Reproduction URL

    https://headlessui.dev/vue/dialog

    Describe your issue

    No transitions take place when dialog initially appears or after closing/opening it again. Transition on close seems to work though. It used to work in v1.6.4.

  • 12

    Slideover/Modal does not cover the full page if input is focused on Safari (iOS)

    What package within Headless UI are you using?

    @headlessui/vue

    What version of that package are you using?

    v1.7.2

    What browser are you using?

    Safari

    Reproduction URL

    I used the code from "Wide create project form example" from tailwindui. As it's not free, I will not paste it here.

    Describe your issue

    If a slideover has an input, the height of the slideover is cropped if this input is focused. This does not happen on Safari on macOS, button Safari on iOS (I used Xcode's simulator to recreate the example I am attaching here).

    https://user-images.githubusercontent.com/23051150/191594958-927d2cb6-e31b-4148-b9d5-7d9616aafbc6.mp4

    Bildschirmfoto 2022-09-21 um 21 28 51@2x

  • 13

    Transition does not call `afterLeave` when using nested Transition.Child

    What package within Headless UI are you using?

    @headlessui/react

    What version of that package are you using?

    v1.7.2

    What browser are you using?

    Chrome

    Reproduction URL

    https://codesandbox.io/s/headlessui-transition-bug-afterleave-3k435m?file=/src/App.tsx:666-1441

    1. Open link above
    2. Open console of Code Sandbox
    3. Click on the "Click to transition" button
    4. Observe that console.log('unmount') in afterLeave callback never gets called.

    Describe your issue

    When using a nested Transition.Child within a Transition component, the afterLeave callback from the Transition component doesn't get called when the exit transition ends.

    Related: https://github.com/tailwindlabs/headlessui/issues/1364

  • 14

    [Vue] - Tabs not working properly when conditionally updating the `selected-index` prop from the `change` event

    What package within Headless UI are you using?

    @headlessui/vue

    What version of that package are you using?

    v1.7.1

    What browser are you using?

    Chrome Latest

    Reproduction URL

    https://codesandbox.io/s/awesome-thompson-ytuh1o?file=/src/App.vue

    Describe your issue

    I have forms within TabPanel and I want to implement a "Discard changes" confirmation before switching to another tab, if there are unsaved changes.

    I tried implementing this with a custom modal and the built in one, but it doesn't work properly.

    When I press Cancel, instead of getting back to the browser, the click event triggers again and again and it enters a permanent loop.

    What I'm trying to use is a controlled component, I'm using the change event to conditionally determine whether or not the user should move to the new tab.

  • 15

    Unexpected keyboard focus behaviour on Popover with portalled panel

    What package within Headless UI are you using?

    @headlessui/react

    What version of that package are you using?

    v1.6.6

    What browser are you using?

    Tested in Firefox and Chromium

    Reproduction URL https://codepen.io/simondl/pen/ZEoWQBq?editors=1010

    Describe your issue I'm using the Popover component and the Popover.Panel is portalled to a different DOM node.

    I expect that when the keyboard focus moves out of the Popover.Panel, it is placed back on the Popover.Panel. Instead, it is being placed on the sibling element of the Popover.Panel in the portalled location.

    The linked codepen shows the same popover component in two different DOM structure. And shows a small reproduction recipe. Case (1) shows exactly my error case. Case (2) shows a different DOM structure, where the focus is handled to my expectation.

    Potential cause The focus-sentinels are only rendered when isPortalled is true (see popover.tsx#L753).

    In my case, isPortalled is false. Therefore, the focus-sentinels are not rendered and there is no special focus handling.

    The reason is, that the isPortalled check only returns true if button and panel are descendants of different 'root' elements.

        for (let root of document.querySelectorAll('body > *')) {
          if (Number(root?.contains(button)) ^ Number(root?.contains(panel))) {
            return true
          }
        }
    

    taken from popover.tsx#L219

    I believe this check is flawed. In my case, button and panel are part of the same 'root' element, but within that in very different locations.

    I believe a better condition for isPortalled might be to check if Button and Panel are direct siblings. That way, the focus-sentinels would render whenever the native browser focus management would not suffice.

  • 16

    Popover.Button stops propagation of drag events

    What package within Headless UI are you using?

    @headlessui/react

    What version of that package are you using?

    For example: v1.6.6

    What browser are you using?

    Chrome

    Reproduction URL

    Describe your issue

    <Popover.Button> stops propagation of click and mouseDown events, which I presume blocks drag events too.