[Feat]: Add asyncInit option for non-blocking dimension measurement#1328
Open
dlabadini wants to merge 5 commits intodavidjerleke:masterfrom
Open
[Feat]: Add asyncInit option for non-blocking dimension measurement#1328dlabadini wants to merge 5 commits intodavidjerleke:masterfrom
dlabadini wants to merge 5 commits intodavidjerleke:masterfrom
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move createEngine + SsrHandler inside the ResizeObserver callback so no synchronous offsetWidth/Height reads occur with asyncInit - Emit 'reinit' after async init completes so framework wrappers re-evaluate canGoToNext/canGoToPrev (fixes hidden nav arrows) - Guard cloneEngine against missing engine
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Embla reads
offsetWidth/offsetHeightsynchronously duringactivate()to compute slide dimensions. In frameworks like React, these reads happen insideuseEffect— after React's DOM commit has written class/style changes from other components. This cross-component write-then-read forces a synchronous browser reflow, blocking the main thread.This is increasingly problematic as pages render more carousels (e.g., discovery pages with 8+ carousels), and as frameworks move toward concurrent/deferred rendering where effects interleave.
Related: #1321 (sync reInit inside ResizeObserver), #1326 (SSR plugin extraction)
Solution
Add an
asyncInitoption (default:false) that usesResizeObserverfor initial dimension measurement instead of synchronousoffsetWidth/offsetHeightreads.When
asyncInit: true:activate()sets up aResizeObserveron the container + slidesborderBoxSizedimensions (no layout read)The one-frame delay (~16ms) between mount and interactive is invisible to users — the carousel is already visually rendered via CSS, just not yet draggable/snappable.
When
asyncInit: false(default): current sync behavior, fully backward compatible.Design decisions
requestAnimationFramewould still requireoffsetWidthreads.borderBoxSize: Available in all modern browsers (Chrome 84+, Firefox 92+, Safari 15.4+). More accurate thanoffsetWidthfor elements with box-sizing variations.deActivate()using the existing cleanup infrastructure.Test plan
asyncInit: falsebehaves identically to current behaviorasyncInit: trueproduces same snap positions after observer firesasyncInit: truedestroy()during async init cancels observer cleanly🤖 Generated with Claude Code