diff --git a/.changeset/gold-humans-tap.md b/.changeset/gold-humans-tap.md new file mode 100644 index 00000000000..eafb21a263e --- /dev/null +++ b/.changeset/gold-humans-tap.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +SelectPanel: Lock body scroll when modal variant is on. diff --git a/packages/react/src/SelectPanel/SelectPanel.module.css b/packages/react/src/SelectPanel/SelectPanel.module.css index 3a999ad1a60..7fc46e2b1fb 100644 --- a/packages/react/src/SelectPanel/SelectPanel.module.css +++ b/packages/react/src/SelectPanel/SelectPanel.module.css @@ -226,7 +226,7 @@ } .Backdrop { - position: absolute; + position: fixed; inset: 0; background-color: var(--overlay-backdrop-bgColor); } diff --git a/packages/react/src/SelectPanel/SelectPanel.test.tsx b/packages/react/src/SelectPanel/SelectPanel.test.tsx index de52939b1ac..743d41aa0b9 100644 --- a/packages/react/src/SelectPanel/SelectPanel.test.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.test.tsx @@ -1193,6 +1193,36 @@ for (const usingRemoveActiveDescendant of [false, true]) { expect(screen.getByRole('button', {name: 'Save'})).toBeInTheDocument() expect(screen.getByRole('button', {name: 'Cancel'})).toBeInTheDocument() }) + + it('locks body scroll when modal is open', async () => { + const user = userEvent.setup() + + renderWithProp( {}} />, usingRemoveActiveDescendant) + + expect(document.body.style.overflow).not.toBe('hidden') + + await user.click(screen.getByText('Select items')) + + await waitFor(() => { + expect(document.body.style.overflow).toBe('hidden') + }) + }) + + it('restores body scroll when modal is closed', async () => { + const user = userEvent.setup() + + renderWithProp( {}} />, usingRemoveActiveDescendant) + + await user.click(screen.getByText('Select items')) + await waitFor(() => { + expect(document.body.style.overflow).toBe('hidden') + }) + + await user.click(screen.getByRole('button', {name: 'Cancel'})) + await waitFor(() => { + expect(document.body.style.overflow).not.toBe('hidden') + }) + }) }) describe('sorting', () => { diff --git a/packages/react/src/SelectPanel/SelectPanel.tsx b/packages/react/src/SelectPanel/SelectPanel.tsx index 04667503618..0b8162ca50b 100644 --- a/packages/react/src/SelectPanel/SelectPanel.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.tsx @@ -362,9 +362,9 @@ function Panel({ [items, itemsInViewSet, onSelectedChange, selected], ) - // disable body scroll when the panel is open on narrow screens + // disable body scroll when the panel is open in modal mode or on narrow screens useEffect(() => { - if (open && isNarrowScreenSize && usingFullScreenOnNarrow) { + if (open && (variant === 'modal' || (isNarrowScreenSize && usingFullScreenOnNarrow))) { const bodyOverflowStyle = document.body.style.overflow || '' // If the body is already set to overflow: hidden, it likely means // that there is already a modal open. In that case, we should bail @@ -379,7 +379,7 @@ function Panel({ document.body.style.overflow = bodyOverflowStyle } } - }, [isNarrowScreenSize, open, usingFullScreenOnNarrow]) + }, [isNarrowScreenSize, open, usingFullScreenOnNarrow, variant]) useEffect(() => { if (open) {