headlessui
headlessui copied to clipboard
Popover enabling `:focus-visible` state on mouse interaction
What package within Headless UI are you using?
@headlessui/react @headlessui/vue
What version of that package are you using?
v1.6.6
What browser are you using?
Chrome
Reproduction URL
https://headlessui.com/react/popover https://stackblitz.com/edit/vitejs-vite-93uk6f?file=src/App.jsx
Describe your issue
When I click Popover.Button
it enables :focus-visible
state. AFAIK it should do that only with keyboard interactions. At least that's how regular HTML buttons work.
I see this behaviors but I am not sure if this is on purpose or not. One thing I do know is that once the popover disappears the focus should be disabled. Can someone confirm whether it is supposed to be enabled or not at all? I would love to help with this issue.
This can't be on purpose. This is not how :focus-visible
is supposed to work. Also if you clicked an <a>
or a <button>
before interacting with Popover.Button
, this doesn't happen.
Removing the following lines fixes the issue. In my opinion these manual focus calls are unnecessary. If I click somewhere with my mouse, I know where my focus is going to.
https://github.com/tailwindlabs/headlessui/blob/5af3bd4b7164a0205ac70c179d8e9651afbb0a72/packages/%40headlessui-react/src/components/popover/popover.tsx#L266-L269 https://github.com/tailwindlabs/headlessui/blob/5af3bd4b7164a0205ac70c179d8e9651afbb0a72/packages/%40headlessui-react/src/components/popover/popover.tsx#L422
Also there are similar focus related issues with other components too.
Modal component:
- Click "Open Dialog"
- Press Tab on your keyboard, "Got it, thanks!" button will get its
focus-visible
styles as expected - Click outside
- Unexpectedly "Open Dialog" button has
focus-visible
styles despite closing the modal with mouse.
Tabs component:
- Clicking on the second tab will cause focus flash around the tab.
Yup just encountered this on the vue tab component, odd enough when I click another button on the screen the behavior becomes the expected one. Not sure if some off ergonomic around focus-visible or the proposed fix covers it.
Reproduction URL https://stackblitz.com/github/gcavanunez/unknown-tab/tree/focus-visible-issue
I get :focus-visible
on links when a modal is opened with a mouse. For some reason I could only reproduce it with Next.js
Minimal reproduction: https://stackblitz.com/edit/github-vhafgm?file=pages/index.tsx

Hoping we can improve this but it might be out of our hands — we do need to programmatically focus things a lot in Headless UI for accessibility reasons and often the browser treats that programmatic focusing as if it were keyboard driven and triggers a focus indicator even though I totally agree that we don't want it to.
On our own sites we use the PostCSS focus-visible polyfill still and not the native :focus-visible
pseudo class because it behaves better in this way. Fingers crossed there's some trick we can come up with that works though — hate seeing focus styles when using the mouse.
I have to click 2 times on the popover here: https://headlessui.com/vue/popover and the only browser that works at first click is firefox. Any update on this?
As a quick, rudimental fix, the following helped me out for the Tab
component in React:
<Tab
onClick={() => {
requestAnimationFrame(() => {
if (document.activeElement instanceof HTMLElement) {
document.activeElement.blur();
}
});
}}
>
…
</Tab>
Any update on this?
In VueJS I was able to fix the first focus (when we click on the PopoverButton) by using this:
const onPopoverClick = async () => {
await nextTick()
document.activeElement.blur()
}
But how to catch the event when Popover closes? Popover doesn't fire any events. It's possible, I guess, to put a global event handler that blurs Popover, but looks hacky.
Also, if I set PopoverButton to be a link (by using as="a"
), the issue disappears, but the tab focus stops working. Maybe it's easier to fix in this case, since Popovers are often used in navigation which is typically a set of links. So I would prefer to use a link, but how to make the tab focus work in this case?
Not sure if it's just me, but even after adding the postcss-focus-visible polyfill in Tailwind 3.0+ using JIT, it still doesn't work on the popover as a default button. Instructions here on adding postcss-focus-visible
in postcss.config.js
https://github.com/tailwindlabs/tailwindcss/issues/3325#issuecomment-758138286
Hey, thank you for this bug report! 🙏
This should be fixed by #2347, and will be available in the next release.
However, it will require a bit of setup to make it behave how you want exactly because right now there is no way to control this behavior via a browser API.
I wrote more about the solution in the PR itself and how you can make it work: https://github.com/tailwindlabs/headlessui/pull/2347#issue-1615619877
You can use the insiders builds to play with the fix:
-
npm install @headlessui/react@insiders
. -
npm install @headlessui/vue@insiders
. -
npm install @headlessui/tailwindcss@insiders
.
I also updated the original reproduction URL shared by @sibbng using the above versions, I also made sure to:
- Add the
@headlessui/tailwindcss
plugin to thetailwind.config.js
- Updated the
focus-visible:
variants in the template withui-focus-visible:
Link: https://stackblitz.com/edit/vitejs-vite-mggdgh?file=src/App.jsx
Hey, thank you for the fix!
I played with the @insiders version. While it works great for resolving this exact issue, it doesn't seem to be working for child elements using group
.
I added group-ui-focus-visible:bg-black
to the chevron: https://stackblitz.com/edit/vitejs-vite-8hakuu?file=src%2FApp.jsx
It appears as if there is no group-focus-visible equivalent for the Headless UI Tailwind plugin. Am I missing something?
You can remove focus-visible
by adding this classname focus-visible:outline-none
:
<Popover className="relative">
<Popover.Button className="... focus-visible:outline-none">
<VscInfo className="ml-4 h-7 w-7 cursor-pointer text-gray-200" />
</Popover.Button>
...
You can remove
focus-visible
by adding this classnamefocus-visible:outline-none
:
you just saved me from more hours searching for the right flag. Thanks.!