Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SelectPanel2: Only render children when open #4348

Merged
merged 5 commits into from
Mar 7, 2024

Conversation

siddharthkp
Copy link
Member

By default a <dialog> renders as open="false", but it does exist in the dom. This can be unintuitive in the react paradigm where you expect dialog to not be rendered in the dom until it's visible.

Places where this shows up:

  1. Data fetching: Data that is meant to be fetched only when the Dialog is open might be fetched early
  2. Testing: When there are multiple dialogs on the page, unless you are more specific, getting element by role dialog returns the first dialog, not the open dialog. screen.getByRole('dialog')
  3. Imperative code: When there are multiple dialogs on the page, querySelector for dialog would return the first dialog, not necessarily the open dialog.

Before:

<!-- closed state: -->
<button type="button" aria-haspopup="true" aria-expanded="false"></button>
<dialog></dialog>
<!-- open state -->
<button type="button" aria-haspopup="true" aria-expanded="true"></button>
<dialog open></dialog>

After:

<!-- closed state: -->
<button type="button" aria-haspopup="true" aria-expanded="false"></button>
- <dialog></dialog>
<!-- open state -->
<button type="button" aria-haspopup="true" aria-expanded="true"></button>
<dialog open></dialog>

Copy link

changeset-bot bot commented Mar 4, 2024

🦋 Changeset detected

Latest commit: 828df34

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@primer/react Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@siddharthkp siddharthkp self-assigned this Mar 4, 2024
Copy link
Contributor

github-actions bot commented Mar 4, 2024

size-limit report 📦

Path Size
packages/react/dist/browser.esm.js 113.71 KB (0%)
packages/react/dist/browser.umd.js 114.38 KB (0%)

@siddharthkp siddharthkp marked this pull request as ready for review March 7, 2024 10:56
@siddharthkp siddharthkp requested a review from a team as a code owner March 7, 2024 10:56
Copy link
Member

@keithamus keithamus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid doing this because it can cause issues for AT users. If we need to set up a button that points to a dialog, it cannot if the dialog is not on the page. For example, your examples are missing aria-details which sets up said relationship:

<button type="button" aria-haspopup="true" aria-expanded="true" aria-details="my-dialog"></button>
<dialog id="my-dialog" open></dialog>

To address some of your points:

Data fetching: Data that is meant to be fetched only when the Dialog is open might be fetched early

Code should avoid doing this, but we could render the dialog and skip the children rendering, if we deem it necessary. The problem, however, is that complex dialogs will experience slow INP if we end up rendering a lot of DOM as the dialog is rendered.

Testing: When there are multiple dialogs on the page, unless you are more specific, getting element by role dialog returns the first dialog, not the open dialog. screen.getByRole('dialog')

This seems true for all elements, no? I would not expect div to return anything but the first div, why would dialog be any different?

Imperative code: When there are multiple dialogs on the page, querySelector for dialog would return the first dialog, not necessarily the open dialog.

Is there an instance where there is a negative effect here? Same applies, as above I believe.


If there are concrete examples of where this is causing failure points we should investigate those.

I think for this PR to land I'd expect to see the <dialog> always be rendered, and other mitigations put in place to directly address the concrete failure modes.

@siddharthkp
Copy link
Member Author

siddharthkp commented Mar 7, 2024

If we need to set up a button that points to a dialog, it cannot if the dialog is not on the page.
For example, your examples are missing aria-details which sets up said relationship

Interesting! This did not come up in the a11y spec, let me confirm with them once more.

but we could render the dialog and skip the children rendering, if we deem it necessary.

I think that's a fair solution, let me try that and see if it has any unintended side effects.

If there are concrete examples of where this is causing failure points we should investigate those.

There are concrete examples of this in dotcom 😢 I've lost multiple days at this point debugging jest tests in dotcom because of these. Folks I talked to were genuinely surprised by behavior. Honestly, it comes back to this:

This (having an element that is not yet "open" or visible but calls its effects) can be unintuitive in the react paradigm where you expect dialog to not be rendered in the dom until it's visible.

@siddharthkp
Copy link
Member Author

Updated!

Rendering the dialog but not its contents now. It solves the main user-land problem (side effects & data fetching), but not the one with selectors in testing which I think is okay for now.

@siddharthkp siddharthkp changed the title experimental/SelectPanel: Only render dialog when open experimental/SelectPanel: Only render children when open Mar 7, 2024
Copy link
Member

@keithamus keithamus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks for updating this!

@siddharthkp siddharthkp added this pull request to the merge queue Mar 7, 2024
Merged via the queue into main with commit c64e5b2 Mar 7, 2024
30 checks passed
@siddharthkp siddharthkp deleted the drafts-selectpanel-only-render-when-open branch March 7, 2024 16:47
@primer primer bot mentioned this pull request Mar 7, 2024
@siddharthkp siddharthkp changed the title experimental/SelectPanel: Only render children when open SelectPanel2: Only render children when open Mar 19, 2024
lukasoppermann pushed a commit that referenced this pull request Apr 16, 2024
* only render Overlay when open

* Create fair-cooks-return.md

* Update fair-cooks-return.md

* render dialog but not contents when closed

* Update fair-cooks-return.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants