shoelace: Handler violations when using SL with SvelteKit

Describe the bug

I’m running into handler violations where event handlers took too much time to return (for instance focusin of modals and drawers taking seconds to process).

To Reproduce I made repro repo available here https://github.com/brgrz/sl-bugs

Steps to reproduce the behavior:

  1. Clone the repo
  2. Run npm i
  3. Run npm run dev, it will run the SvelteKit app at http://localhost:3000
  4. Open Chrome + devtools, in Devtools->Console tab->select All issues (or Verbose)
  5. Open the app, click the Open drawer button
  6. Inside the drawer try clicking around on the whitespace, try clicking into the input and then onto the whitespace and so forth
  7. You should be seeing instances of [Violation] 'focusin' handler took 6519ms in the Console (while this happens, the app will freeze preventing you to click on anything else)

Expected behavior No freezes, no violations/timeouts

Desktop (please complete the following information):

  • OS: Windows 10
  • Browser Chrome, Edge, both latest BUT was unable to reproduce this in Firefox

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 28 (25 by maintainers)

Most upvoted comments

Turns out the logic here wasn’t needed since we’re also iterating over child elements. This was causing some unintended recursion where the same elements were returned over and over again.

I’ve verified the fix works for the use case above, as well as with additional nested elements. This fix will land in beta.45.

I was able to repro this outside of SvelteKit: https://jsfiddle.net/geoffrich/pub0orke/

I reduced the example a bit, but the key difference is one line: document.body.tabIndex = -1. SvelteKit sets tabIndex on the body so it can reset focus on client-side navigation. This repros the issue in the JSFiddle you linked. Interestingly, this only happens in Chrome/Edge, not in Firefox (I’m on Windows).

The issue is in these lines: https://github.com/shoelace-style/shoelace/blob/1c010ffe5adaf9c2ffda8b818ee45a4feb359132/src/internal/modal.ts#L36-L40

For whatever reason, when tabindex is set on the body and you click inside the panel but not on one of the nested inputs, path is equal to [body, html, document, window], which does not include this.element. This causes getTabbableElements to be run. When a sl-select is also in the drawer, it finds ~68k elements, causing the page to hang.

To make it easier to repro, I set a border on the tab panel. Clicking the white space inside the border in Chrome will cause the issue.

This is really a “perfect storm” issue, since the following need to be true: EDIT: not entirely accurate, see my next comment.

  • ~tabindex has to be set on the body~
  • ~browser has to be Chromium-based~
  • tab panel has be inside the drawer
  • something with a lot of nested elements like sl-select also has to be inside the drawer