Skip to content

feat: add scrollLock prop to control body scroll lock#564

Merged
zombieJ merged 2 commits into
react-component:masterfrom
EmilyyyLiu:feat/scroll-lock
Jun 5, 2026
Merged

feat: add scrollLock prop to control body scroll lock#564
zombieJ merged 2 commits into
react-component:masterfrom
EmilyyyLiu:feat/scroll-lock

Conversation

@EmilyyyLiu

@EmilyyyLiu EmilyyyLiu commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Add scrollLock prop to control whether to lock body scroll when dialog opens.

Background

Related issue: #32567

Users want to be able to interact with background elements when modal is open. Currently, the modal locks body
scroll by default.

Solution

Add scrollLock prop (default: true) to control body scroll lock behavior.

API

<Modal scrollLock={false}>
  {/* User can interact with background */}
</Modal>

- scrollLock={true} (default): Lock body scroll (existing behavior)
- scrollLock={false}: Do not lock body scroll

Changelog

│ Language │ Changelog │

│ 🇺🇸 English │ Add scrollLock prop to control whether to lock body scroll when dialog opens │

│ 🇨🇳 Chinese │ 新增 scrollLock 属性,用于控制对话框打开时是否锁定 body 滚动 │

Summary by CodeRabbit

发布说明

  • 新功能
    • 添加 scrollLock 配置项(默认启用),允许用户控制对话框打开时是否锁定页面滚动。

@vercel

vercel Bot commented Jun 4, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the React Component Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6baae2bc-4860-45ab-8dd2-774a8c647982

📥 Commits

Reviewing files that changed from the base of the PR and between 9c45c3c and cb61b22.

📒 Files selected for processing (4)
  • README.md
  • src/DialogWrap.tsx
  • src/IDialogPropTypes.ts
  • tests/scroll.spec.tsx
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/scroll.spec.tsx
  • src/DialogWrap.tsx

Walkthrough

Dialog 组件新增 scrollLock 属性,允许开发者控制打开对话框时是否锁定 body 滚动。实现通过在 DialogWrap 中解构该属性并根据其值调整 Portal 的 autoLock 逻辑,配合类型定义、测试用例和文档说明完成。

Changes

scrollLock 功能开关

Layer / File(s) Summary
scrollLock 属性类型定义
src/IDialogPropTypes.ts
在 IDialogPropTypes 接口中新增可选的 scrollLock?: boolean 字段,说明其用于控制弹窗打开时是否锁定 body 滚动。
DialogWrap 实现与 Portal 自动锁定控制
src/DialogWrap.tsx
DialogWrap 解构 scrollLock 属性(默认 true),将其从 restProps 中分离以避免向内部 Dialog 透传,并修改 Portal 的 autoLock 为 scrollLock && (visible || animatedVisible),使滚动锁定能力受该属性开关控制。
测试用例与 API 文档
tests/scroll.spec.tsx, README.md
新增两条测试用例分别验证 scrollLock={false} 时 body 不被锁定和 scrollLock={true} 时 body 被锁定的行为,并在 README 的 API 属性表中记录 scrollLock 配置项的类型、默认值及其用途说明。

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • react-component/dialog#472:两个 PR 都涉及对话框的滚动锁定生命周期——本 PR 通过新增 scrollLock 属性控制 Portal 的 autoLock,而 PR #472 则调整对话框关闭时的解锁行为。

Suggested reviewers

  • zombieJ

Poem

🐰 一纸 scrollLock,锁住身躯不摇晃,
body 滚不滚,开关说了算。
Portal 听令,autoLock 随之响,
测试来把关,文档来护航。✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 标题清晰准确地总结了主要变更:添加 scrollLock prop 用于控制 body 滚动锁定,与所有代码改动(README、组件 props、类型定义、测试)完全一致。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/DialogWrap.tsx

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

src/IDialogPropTypes.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

tests/scroll.spec.tsx

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread tests/scroll.spec.tsx Fixed
Comment thread tests/scroll.spec.tsx Fixed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new scrollLock prop (defaulting to true) to control whether the body scroll is locked when the dialog opens. The feedback suggests extracting scrollLock from the props passed down to the underlying Dialog component to prevent potential React console warnings about unknown DOM attributes. Additionally, improvements to the new test cases are recommended, such as removing unused destructured variables, correcting test descriptions, and adding a test case to verify dynamic updates of the scrollLock prop.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/DialogWrap.tsx
Comment thread src/DialogWrap.tsx Outdated
Comment thread tests/scroll.spec.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/IDialogPropTypes.ts (1)

1-1: ⚠️ Potential issue | 🟠 Major

修复 @rc-component/util/lib/PortalWrapper 导入以消除 no-restricted-imports

CI 标记 src/IDialogPropTypes.ts 第 1 行的导入触发 no-restricted-imports@rc-component/util 根入口 index.d.ts 已导出 GetContainerexport type { GetContainer } from './PortalWrapper';),因此应将 GetContainer 的导入改为从包根导入以通过检查;仓库内仅此处使用 GetContainer,影响面很小。该问题虽非本次 PR 引入,但建议合并前一并修复。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/IDialogPropTypes.ts` at line 1, 在 IDialogPropTypes.ts 中将对类型 GetContainer
的导入从受限子路径 '`@rc-component/util/lib/PortalWrapper`' 改为从包根 '`@rc-component/util`'
导入以通过 no-restricted-imports 检查;具体操作是替换当前 import type { GetContainer } from
'`@rc-component/util/lib/PortalWrapper`' 为 import type { GetContainer } from
'`@rc-component/util`'(确保只修改导入语句,保留类型引用不变)。
🧹 Nitpick comments (1)
tests/scroll.spec.tsx (1)

83-83: 💤 Low value

可选:移除未使用的 rerender 变量。

两个新增的测试用例中都解构了 rerender 变量但未使用。可以简化为仅解构 unmount

♻️ 建议的清理
-    const { unmount, rerender } = render(<Dialog visible scrollLock={false} />);
+    const { unmount } = render(<Dialog visible scrollLock={false} />);
-    const { unmount, rerender } = render(<Dialog visible scrollLock={true} />);
+    const { unmount } = render(<Dialog visible scrollLock={true} />);

Also applies to: 94-94

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/scroll.spec.tsx` at line 83, Two tests destructure an unused rerender
from the render result in tests/scroll.spec.tsx; remove the unused variable to
clean up the code by changing occurrences where you do const { unmount, rerender
} = render(<Dialog ... />) to only destructure const { unmount } =
render(<Dialog ... />). Update both instances (the one around the
scrollLock=false test and the other referenced at the second occurrence) so
rerender is not declared if unused.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/IDialogPropTypes.ts`:
- Line 1: 在 IDialogPropTypes.ts 中将对类型 GetContainer 的导入从受限子路径
'`@rc-component/util/lib/PortalWrapper`' 改为从包根 '`@rc-component/util`' 导入以通过
no-restricted-imports 检查;具体操作是替换当前 import type { GetContainer } from
'`@rc-component/util/lib/PortalWrapper`' 为 import type { GetContainer } from
'`@rc-component/util`'(确保只修改导入语句,保留类型引用不变)。

---

Nitpick comments:
In `@tests/scroll.spec.tsx`:
- Line 83: Two tests destructure an unused rerender from the render result in
tests/scroll.spec.tsx; remove the unused variable to clean up the code by
changing occurrences where you do const { unmount, rerender } = render(<Dialog
... />) to only destructure const { unmount } = render(<Dialog ... />). Update
both instances (the one around the scrollLock=false test and the other
referenced at the second occurrence) so rerender is not declared if unused.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ee979be0-5bb2-4314-b89e-666e8f962ea9

📥 Commits

Reviewing files that changed from the base of the PR and between 16c0f83 and dcca31a.

📒 Files selected for processing (4)
  • README.md
  • src/DialogWrap.tsx
  • src/IDialogPropTypes.ts
  • tests/scroll.spec.tsx

@codecov

codecov Bot commented Jun 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.93%. Comparing base (9105b08) to head (cb61b22).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #564      +/-   ##
==========================================
+ Coverage   98.92%   98.93%   +0.01%     
==========================================
  Files           8        8              
  Lines         186      188       +2     
  Branches       67       68       +1     
==========================================
+ Hits          184      186       +2     
  Misses          2        2              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

刘欢 and others added 2 commits June 5, 2026 15:10
- Add scrollLock prop (default: true) to control whether to lock body scroll when dialog opens
- Add test cases for scrollLock functionality
- Update README.md with new prop documentation

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@zombieJ zombieJ left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍 实现简洁正确:scrollLock={false} 时 autoLock 短路,useScrollLocker 不会给 body 注入 overflow:hidden;默认 true 保持原行为,向后兼容。+1

@zombieJ zombieJ merged commit 3ebf65c into react-component:master Jun 5, 2026
9 of 10 checks passed
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.

3 participants