fix(ui): group field not forwarding forceRender to nested fields - #17715
Open
vjymisal0 wants to merge 1 commit into
Open
fix(ui): group field not forwarding forceRender to nested fields#17715vjymisal0 wants to merge 1 commit into
vjymisal0 wants to merge 1 commit into
Conversation
The Group field component never forwarded its `forceRender` prop to the RenderFields calls it renders internally, unlike sibling iterable field types (Row, Tabs) which correctly forward it. When an Array row is force-rendered (e.g. top-level document fields are always force-rendered) but contains only a single Group field, the Group's own child fields fell back to lazy IntersectionObserver based rendering instead of rendering immediately. Combined with the Collapsible/AnimateHeight height measurement (which measures `scrollHeight` while the row content is still `display: none`), conditional fields nested in that Group would race with the IntersectionObserver callback and fail to render on the first expand of a row that started collapsed. Collapsing and expanding again worked because the fields, once mounted, stay mounted. Fixes payloadcms#15613
vjymisal0
requested review from
AlessioGr,
JarrodMFlesch and
jacobsfletch
as code owners
August 7, 2026 17:25
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.
Which branch should this PR target?
main(v4 development) — the bug reproduces on the currentmainUI code as well as v3.What?
The
Groupfield component never forwarded itsforceRenderprop down to theRenderFieldscalls it renders internally for its own sub-fields. Sibling iterable field types (Row,Tabs) already correctly forwardforceRender.Why?
Fixes #15613 — "Array with a single group containing conditional fields does not render on first collapsible expand".
Top-level document fields are always rendered with
forceRender(seeDocumentFields), which flows down throughArray→ArrayRow→ the row's own fields. When an array row contains a singleGroupfield, thatforceRenderreached theGroupcomponent but was silently dropped instead of being passed to theRenderFieldscall for the group's own child fields.Without
forceRender, those child fields fall back to lazy,IntersectionObserver-gated rendering (RenderIfInViewport). While an array row is collapsed, its content lives inside an ancestor withdisplay: none(set byAnimateHeight), so the observer never reports an intersection. On first expand,AnimateHeight's height-animation helper (usePatchAnimateHeight) measurescontent.scrollHeightin the same effect flush in which the siblingdisplay: noneremoval hasn't committed to the DOM yet, so it measures0and pins the row's container height to0px. That keeps the (still not-yet-mounted) conditional fields clipped and unable to ever report an intersection, so they never mount — appearing "empty". Collapsing and expanding again works because, on the previous cycle, the fields (once mounted) stay mounted, so the height measurement is now accurate.Forwarding
forceRenderthroughGroup(matchingRow/Tabs) makes the group's child fields mount immediately alongside the rest of the row's force-rendered content, avoiding the race entirely.How?
packages/ui/src/fields/Group/index.tsx: destructureforceRenderfrom props and pass it to bothRenderFieldscalls (named-group and unnamed-group paths).collapsedGroupWithConditionto the Array fields test collection: aninitCollapsedarray with a default row containing a singlegroupfield with a conditional (admin.condition) text field.test/fields/collections/Array/e2e.spec.tsthat loads the create page, confirms the row starts collapsed, expands it once, and asserts the conditional field is visible on that very first expand.Test status
I was unable to run the test suite in my environment (no disk space available to
pnpm installthe monorepo's dependencies — the working environment had under 3GB free). I've verified the fix by tracing the actual render/measurement code paths (Group,Row,Tabs,RenderFields,RenderIfInViewport,useIntersect,AnimateHeight,usePatchAnimateHeight) and confirmedGroupwas the only iterable field type not forwardingforceRender, which is a clear, minimal, and type-safe fix (forceRenderis already part ofGroupFieldClientPropsviaClientFieldBase). I was not able to executepnpm test:e2elocally to confirm the new test passes — please run it in CI.Fixes #15613