department-of-veterans-affairs / vets-design-system-documentation

Repository for design.va.gov website
https://design.va.gov
37 stars 57 forks source link

va-radio component delayed when rendering inner shadow DOM elements #1558

Open nickjg231 opened 1 year ago

nickjg231 commented 1 year ago

Bug Report

What happened

Slack convo: https://dsva.slack.com/archives/CBU0KDSB1/p1676479946812439

Currently inside of the va-radio web component, there is an issue with the speed at which shadow DOM elements are rendered. In Robin's case from the ticket:

while web pack is rebuilding the site, the shadow DOM can take over a second to render

Here is a CodeSandbox of the issue. When the code initially runs and queries for an <h3> element within the va-radio shadow DOM, no <h3> element is found. After a 1 second timeout, the <h3> element is found.

What I expected to happen

The <h3> element (and other shadow DOM elements available on render) inside of the va-radio component should be selectable without needing to delay the query selector.

Reproducing

Steps to reproduce:

  1. Open the CodeSandbox
  2. Open dev tools and look at the console
  3. The <h3> element is only output to the console once, even though the findAndFocusH3 function runs twice

Urgency

How urgent is this request? Please select the approriate option below and/or provide details

This is affecting current work, but a workaround is to use a setInterval function to keep checking whether the <h3> element is found. Once found, normal logic may proceed (In this case, setting focus to an element). This workaround is not ideal due to the UX implications of delaying the focus on an element.

Andrew565 commented 1 year ago

Suggested Robin use https://devdocs.io/dom/customelementregistry/whendefined to wait for the va-radio component to 'upgrade' in the browser.

Andrew565 commented 1 year ago

whenDefined was not an effective solution, this ticket will remain open for now and should be prioritized eventually.

humancompanion-usds commented 9 months ago

@caw310 and @micahchiang - Please prioritize looking into this in the next sprint. This is blocking forms work.

caw310 commented 9 months ago

Hey team! Please add your planning poker estimate with Zenhub @Andrew565 @ataker @harshil1793 @it-harrison @jamigibbs @micahchiang @nickjg231 @powellkerry @rmessina1010 @rsmithadhoc

jamigibbs commented 9 months ago

@humancompanion-usds I just want to mention that Robin mentioned in the original Slack thread that he has a workaround for this just in case the forms library team needed to implement this sooner rather than later:

This is affecting current work, but a workaround is to use a setInterval function to keep checking whether the <h3> element is found. Once found, normal logic may proceed (In this case, setting focus to an element). This workaround is not ideal due to the UX implications of delaying the focus on an element.

Andrew565 commented 9 months ago

There is a simple reason why the h3 is not selectable upon initial load: it doesn't exist yet. Custom Elements/Web Components load a 'placeholder' DOM element when they're initially rendered, and this placeholder does not include anything within the Shadow DOM. Once the Web Component is registered with the browser's Custom Element Registry, then the DOM placeholder is 'upgraded' to include the full content of the Web Component. This is why the whenDefined API (mentioned in an earlier comment) exists. I no longer recall why Robin was unable to make that API work for his needs, but that's still one of the better ways to handle this situation. Using setInterval is another good option, and the delay could likely be reduced to 500ms or lower, rather than waiting a full second, but YMMV.

For a reference of Stencil Web Component Lifecycle: https://stenciljs.com/docs/v2/component-lifecycle

A third, somewhat more annoying to implement but also slightly more 'elegant' solution, would be to add an event to all components that would fire as part of the "connectedCallback" lifecycle that basically would be akin to the 'whenDefined' API. That is, a "this component has rendered" event. It would increase our code surface a little, and would have to be implemented within all components that we wanted, but it would give an event that other people's apps could listen for to tell them when a component has finished rendering.

jeana-adhoc commented 9 months ago

To add more context here, the forms team is starting to look at this for when this h3 becomes the h1 on the page with the new simplified form header, and the focus needs to go to the h1. And sometimes, that h1 might live in a component like radio/checkbox group.