Skip to content

Fix JoinAttrs not joining attributes in nested groups - #335

Open
milanobrtlik wants to merge 1 commit into
maragudk:mainfrom
milanobrtlik:joinattrs-nested-groups
Open

Fix JoinAttrs not joining attributes in nested groups#335
milanobrtlik wants to merge 1 commit into
maragudk:mainfrom
milanobrtlik:joinattrs-nested-groups

Conversation

@milanobrtlik

Copy link
Copy Markdown

JoinAttrs unwraps g.Group only one level deep, so an attribute nested deeper is never
merged. It falls through to the result verbatim, and renderChild, which recurses into groups
at any depth, then emits it as a second attribute of the same name. Browsers keep the first
occurrence, so the value is silently dropped.

Reproduction

Against main @ d1fd82b:

Div(JoinAttrs("class", g.Group{Class("party"), g.Group{Class("gold")}}, Class("hat")))

renders

<div class="party hat" class="gold"></div>

instead of <div class="party gold hat"></div>. With three levels it degrades further —
<div class="a" class="b" class="c d"></div>.

Why it comes up

Two-level groups arise from the composition pattern the docs already show: a component that
forwards g.Group(children) into JoinAttrs, called by another component that does the same.
g.Map also returns a Group, so mapping over data into a JoinAttrs call hits it too. The
existing group test missed this because it forwards an element rather than an attribute, and
elements are appended to result either way.

Fix

Unwrap recursively in processNode, mirroring what renderChild does, so JoinAttrs sees
exactly what will be rendered. Element order is preserved: non-attribute children stay in place
and the joined attribute lands at the position of the first match, same as before.

Four test cases added — two-level, three-level, nested components, and element order inside
nested groups. Existing tests unchanged, coverage stays at 100%.

The doc comment is updated to say groups are transparent, since the previous wording
("Attributes on non-direct descendants are ignored") no longer describes the behaviour.

JoinAttrs unwrapped g.Group only one level deep, so an attribute nested deeper
was never merged. It fell through to the result verbatim, and renderChild, which
recurses into groups at any depth, then emitted it as a second attribute of the
same name. Browsers keep the first occurrence, so the value was silently dropped.

Two-level groups arise from the documented composition pattern: a component that
forwards g.Group(children) into JoinAttrs, called by another that does the same.
g.Map also returns a Group. The existing group test missed this because it
forwards an element rather than an attribute.

Unwrap recursively in processNode instead, mirroring renderChild, so JoinAttrs
sees exactly what will be rendered.
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.

1 participant