headlessui icon indicating copy to clipboard operation
headlessui copied to clipboard

Popover enabling `:focus-visible` state on mouse interaction

Open sibbng opened this issue 2 years ago • 6 comments

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.

sibbng avatar Jul 18 '22 13:07 sibbng

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.

leonwright avatar Jul 18 '22 23:07 leonwright

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.

sibbng avatar Jul 19 '22 10:07 sibbng

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:

  1. Click "Open Dialog"
  2. Press Tab on your keyboard, "Got it, thanks!" button will get its focus-visible styles as expected
  3. Click outside
  4. 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.

sibbng avatar Jul 21 '22 12:07 sibbng

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

gcavanunez avatar Jul 23 '22 15:07 gcavanunez

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

rookbreezy avatar Jul 26 '22 19:07 rookbreezy

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.

adamwathan avatar Sep 03 '22 00:09 adamwathan

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?

Archetipo95 avatar Sep 30 '22 08:09 Archetipo95

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>

kripod avatar Oct 10 '22 20:10 kripod

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?

victor-ponamariov avatar Jan 02 '23 03:01 victor-ponamariov

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

paulwongx avatar Feb 18 '23 00:02 paulwongx

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 the tailwind.config.js
  • Updated the focus-visible: variants in the template with ui-focus-visible:

Link: https://stackblitz.com/edit/vitejs-vite-mggdgh?file=src/App.jsx

RobinMalfait avatar Mar 10 '23 21:03 RobinMalfait

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

nethzyr avatar Mar 12 '23 10:03 nethzyr

It appears as if there is no group-focus-visible equivalent for the Headless UI Tailwind plugin. Am I missing something?

agusterodin avatar Apr 26 '23 22:04 agusterodin

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>
...

ala-garbaa-pro avatar Jun 11 '23 16:06 ala-garbaa-pro

You can remove focus-visible by adding this classname focus-visible:outline-none:

you just saved me from more hours searching for the right flag. Thanks.!

logemann avatar Jun 12 '23 22:06 logemann