Skip to content

Commit f13a741

Browse files
fix(ui): prevent wrong scroll target when adding rows in repeated array blocks (#15047)
### What? Adding rows to an array field inside repeated Lexical blocks sometimes scrolls to the first block instead of the block where the row was added. ### Why? Row elements share the same DOM id because the parent path isn’t made unique per block in Lexical, so `scrollToID` matches the first occurrence. ### How? Add a block-unique prefix into the array field path/id generation when rendering array fields, ensuring each block’s rows have distinct DOM ids and scroll targets. Fixes: #14333
1 parent fe9119b commit f13a741

File tree

2 files changed

+12
-6
lines changed

2 files changed

+12
-6
lines changed

packages/ui/src/fields/Array/ArrayRow.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type ArrayRowProps = {
4747
readonly rowCount: number
4848
readonly rowIndex: number
4949
readonly schemaPath: string
50+
readonly scrollIdPrefix: string
5051
readonly setCollapse: (rowID: string, collapsed: boolean) => void
5152
} & Pick<ClientComponentProps, 'forceRender'> &
5253
UseDraggableSortableReturn
@@ -77,6 +78,7 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
7778
rowCount,
7879
rowIndex,
7980
schemaPath,
81+
scrollIdPrefix,
8082
setCollapse,
8183
setNodeRef,
8284
transform,
@@ -141,7 +143,7 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
141143
: undefined
142144
}
143145
header={
144-
<div className={`${baseClass}__row-header`}>
146+
<div className={`${baseClass}__row-header`} id={`${scrollIdPrefix}-row-${rowIndex}`}>
145147
{isLoading ? (
146148
<ShimmerEffect height="1rem" width="8rem" />
147149
) : (

packages/ui/src/fields/Array/index.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type {
66
} from 'payload'
77

88
import { getTranslation } from '@payloadcms/translations'
9-
import React, { Fragment, useCallback, useMemo } from 'react'
9+
import React, { Fragment, useCallback, useId, useMemo } from 'react'
1010
import { toast } from 'sonner'
1111

1212
import type { ClipboardPasteData } from '../../elements/ClipboardAction/types.js'
@@ -144,6 +144,9 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => {
144144
validate: memoizedValidate,
145145
})
146146

147+
const componentId = useId()
148+
const scrollIdPrefix = useMemo(() => `scroll-${componentId}`, [componentId])
149+
147150
const addRow = useCallback(
148151
(rowIndex: number) => {
149152
addFieldRow({
@@ -153,10 +156,10 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => {
153156
})
154157

155158
setTimeout(() => {
156-
scrollToID(`${path}-row-${rowIndex}`)
159+
scrollToID(`${scrollIdPrefix}-row-${rowIndex}`)
157160
}, 0)
158161
},
159-
[addFieldRow, path, schemaPath],
162+
[addFieldRow, path, schemaPath, scrollIdPrefix],
160163
)
161164

162165
const duplicateRow = useCallback(
@@ -166,10 +169,10 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => {
166169
setModified(true)
167170

168171
setTimeout(() => {
169-
scrollToID(`${path}-row-${rowIndex}`)
172+
scrollToID(`${scrollIdPrefix}-row-${rowIndex}`)
170173
}, 0)
171174
},
172-
[dispatchFields, path, setModified],
175+
[dispatchFields, path, scrollIdPrefix, setModified],
173176
)
174177

175178
const removeRow = useCallback(
@@ -439,6 +442,7 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => {
439442
rowCount={rows?.length}
440443
rowIndex={i}
441444
schemaPath={schemaPath}
445+
scrollIdPrefix={scrollIdPrefix}
442446
setCollapse={setCollapse}
443447
/>
444448
)}

0 commit comments

Comments
 (0)