Skip to content

Fix x-for reordering with nested templates - #4912

Open
rameel wants to merge 10 commits into
alpinejs:mainfrom
rameel:fix-x-for-nested-reorder
Open

rameel wants to merge 10 commits into
alpinejs:mainfrom
rameel:fix-x-for-nested-reorder

Conversation

@rameel

@rameel rameel commented Sep 19, 2026

Copy link
Copy Markdown

Fix reordering when an x-for template contains nested x-for or x-if templates.

Fixes #4911

Move the rendered range for each keyed x-for item so output from nested
x-if and x-for templates stays attached during reordering
An empty nested loop could leave the parent's saved last-rendered
element pointing at an already removed node, so reordering the parent
later moved the wrong range and detached sibling content.

Recompute the marker from the last live lookup entry and move the
rendered range through its recorded end.
x-for eagerly resolved the last lookup element before storing it, even
though moveBlock resolves the marker chain when reading the block
boundary.

Store the lookup element directly and keep resolution at the use site.
This preserves the links between nested structural directives, allowing
an outer x-for to resolve the current boundary after an inner x-if
removes its rendered child.
moveBlock relocates a contiguous DOM range bounded by its first and last
rendered nodes. Use nextSibling instead of nextElementSibling so the
entire range moves together.

Using nextElementSibling could split the range by leaving intervening
text and comment nodes behind.
Rename getLastRenderedElement to resolveBlockEnd and move it into
utils/blocks.js for reuse
x-for now keeps a chain of links instead of saving a last node that may
later be removed by a nested directive.

Follow this chain before getting the next sibling, so morph continues
after the rendered block instead of inside it.

GPT-6 Astra helped identify the need for this change.
Swapping two items in the data could also move intervening DOM blocks,
causing focused inputs in those blocks to lose focus.

Swap complete DOM ranges so intervening blocks stay connected. Add
regression tests for ordinary elements and nested template blocks.

GPT-6 Astra helped uncover a focus regression.
Bring the x-for tests written during the nested reordering fix into the
main suite.

Cover state preservation, cleanup, changing block boundaries and
combined updates.

Also add morph regression tests for boundary-handling issues identified
with help from GPT-6 Astra.

This branch has not been deployed

No deployments
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.

x-for reorders nested templates incorrectly

1 participant