Skip to content

DialogHelperElement.connectedCallback forces synchronous reflow on page load #3946

@mattcosta7

Description

@mattcosta7

Description

In dialog_helper.ts (L88–L91), the connectedCallback of DialogHelperElement reads body.clientWidth and immediately writes to body.style, forcing a synchronous layout/reflow:

this.ownerDocument.body.style.setProperty(
  '--dialog-scrollgutter',
  `${window.innerWidth - this.ownerDocument.body.clientWidth}px`,
)

Problem

  • body.clientWidth is a layout-dependent property. Reading it forces the browser to synchronously flush any pending style/layout changes to return an accurate value.
  • This runs in connectedCallback, which is invoked during HTML parsing/page load — a performance-critical phase.
  • Every <dialog-helper> element on the page triggers this, so pages with multiple dialogs pay the cost multiple times.
  • This can negatively impact Core Web Vitals (LCP, INP) and overall page load performance.

Suggested fix

Defer the read/write to a requestAnimationFrame callback to avoid blocking initial render:

requestAnimationFrame(() => {
  this.ownerDocument.body.style.setProperty(
    '--dialog-scrollgutter',
    `${window.innerWidth - this.ownerDocument.body.clientWidth}px`,
  )
})

Alternatively, consider whether this can be solved purely in CSS (e.g., using scrollbar-gutter: stable where supported), eliminating the JavaScript measurement entirely.

Additional context

  • It may also be worth deduplicating this work — since --dialog-scrollgutter is set on document.body, only one <dialog-helper> needs to compute it, not every instance.
  • The click event listener registered on document at L86 also lacks deduplication and could be registered multiple times if multiple <dialog-helper> elements exist.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions