Skip to content

feat(Modal): adds zIndex control and renderDismissButton#460

Open
joacotornello wants to merge 7 commits intomasterfrom
feat/modal-zindex-and-dismiss
Open

feat(Modal): adds zIndex control and renderDismissButton#460
joacotornello wants to merge 7 commits intomasterfrom
feat/modal-zindex-and-dismiss

Conversation

@joacotornello
Copy link
Copy Markdown
Contributor

@joacotornello joacotornello commented Apr 24, 2026

Type

  • Bugfix 🐛
  • New feature 🌈
  • Change request 🤓
  • Documentation 📚
  • Tech debt 👩‍💻

Screenshots

Captura de pantalla 2026-04-24 a la(s) 3 52 28 p  m Captura de pantalla 2026-04-24 a la(s) 3 52 42 p  m

Changes proposed ✔️

Summary by CodeRabbit

  • New Features

    • Modal supports a zIndex prop to choose stacking layer ("base" or "top")
    • Modal supports renderDismissButton to show/hide the built-in dismiss control
  • Documentation

    • Added stories/examples: no-dismiss-button and modal-over-sidebar demonstrating stacking and dismissal behavior

@joacotornello joacotornello requested a review from a team as a code owner April 24, 2026 18:02
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 24, 2026

📝 Walkthrough

Walkthrough

Adds z-index tokens (1000, 1100) and propagates them through tokens, theme contract, globals, and CSS properties; refactors modal CSS to expose z-index variants; extends Modal API with zIndex and renderDismissButton; updates tests and stories; small CI and agent configuration changes added.

Changes

Cohort / File(s) Summary
Design system z-index tokens & propagation
packages/core/tokens/src/zIndex/sys.json, packages/core/styles/src/themes/contract.css.ts, packages/core/styles/src/themes/globals.css.ts, packages/core/styles/src/properties/css.ts
Added 1000 and 1100 z-index tokens and comments; expanded theme contract and global theme zIndex map; added "1000" and "1100" to zIndex properties registry.
Modal CSS variant system
packages/core/styles/src/packages/composite/modal/nimbus-modal.css.ts
Removed hardcoded z-index values; introduced variant-based z-index exports (containerZIndex, overlayZIndex, overlayScopedZIndex) and exposed them from styles alongside existing overlay/container styles.
React Modal API & behavior
packages/react/src/composite/Modal/src/Modal.tsx, packages/react/src/composite/Modal/src/modal.types.ts
Added `zIndex?: "base"
Tests & Storybook
packages/react/src/composite/Modal/src/modal.spec.tsx, packages/react/src/composite/Modal/src/modal.stories.tsx
Extended tests to assert dismiss-button visibility, Escape-key dismissal without button, and zIndex variant class selection; refactored stories with shared render helpers; added noDismissButton and modalOverSidebar stories demonstrating zIndex="top".
Agent / CI config
.claude/settings.json, .coderabbit.yaml, .github/workflows/publish-rc.yml
Added .claude/settings.json allowing npx eslint * and git stash *; removed auto_resolve_threads from .coderabbit.yaml; updated publish RC workflow to explicit permissions, OIDC Node setup, and adjusted Yarn/npm auth env handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 inconclusive)

Check name Status Explanation Resolution
Breaking Change Documentation Verification ❌ Error PR #460 introduces breaking changes to CSS module exports (removal of zIndex from container) without corresponding CHANGELOG documentation in the 'Breaking changes' section. Add a '#### 🛠 Breaking changes' section to CHANGELOG.md documenting the CSS module structure changes or maintain backward compatibility by preserving the original container export.
Undocumented Css Breaking Changes ❓ Inconclusive Unable to access repository context or examine CSS changes - shell execution environment not available. Provide the PR diff output, CSS file contents, and CHANGELOG documentation for manual review of undocumented CSS breaking changes.
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required format 'feat(PackageName): Title' and accurately describes the main changes—adding zIndex control and renderDismissButton to the Modal component.
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.
Unversioned Breaking Changes ✅ Passed No breaking changes detected. Two new optional Modal props and design system tokens are backward-compatible additions with appropriate version bumps.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/modal-zindex-and-dismiss

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

@snyk-io-us
Copy link
Copy Markdown

snyk-io-us Bot commented Apr 24, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 24, 2026

Getting started

Please make sure you read our documentation on how to write code for components, stories and styles.

  • Provide a list of changes
  • Include images to help better visualize your work
  • If your PR closes an issue, please link it
  • Add reviewers
  • Add a label to help better understand what your changes are related to

@coderabbitai coderabbitai Bot added the enhancement New feature or request label Apr 24, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.claude/settings.json:
- Line 3: The allow list in .claude/settings.json is overly broad—specifically
the entries "Bash(npx eslint *)" and "Bash(git stash *)" permit wildcard
execution and state-mutating git commands; remove or tighten these entries by
eliminating "Bash(git stash *)" and replacing wildcard Bash allowances with
explicit, least-privilege commands/arguments (e.g., specific npx eslint
subcommands needed) so only the minimal exact commands are permitted; update the
"allow" array to list those exact command signatures instead of wildcard
patterns.

In `@packages/core/styles/src/packages/composite/modal/nimbus-modal.css.ts`:
- Around line 102-109: overlayScoped is a static style hardcoding zIndex[600]
and therefore doesn't follow the zIndex variant model used by overlay
(styleVariants with base/top); change overlayScoped to be a styleVariants (like
overlay) that maps the same zIndex variants (base -> zIndex[600], top ->
zIndex[1000]) and then update the Modal usage for scoped mode to pick the
correct variant (e.g., use modal.classnames.overlayScoped[zIndex] instead of
modal.classnames.overlayScoped) so scoped modals respect the zIndex prop.
- Around line 97-100: The CHANGELOG is missing a breaking-change entry
documenting that the Modal z-index values have migrated to design tokens; add a
breaking-changes bullet to the CHANGELOG.md noting that modal z-index references
(seen in overlay styleVariants using varsThemeBase.zIndex with values
600/1000/1100 via overlay and overlayPortaled) were migrated to design tokens in
v9.0.0, include the affected symbols (overlay, overlayPortaled,
varsThemeBase.zIndex) and a short migration note for consumers to update any
overrides that referenced the numeric z-index keys directly.

In `@packages/react/src/composite/Modal/src/modal.spec.tsx`:
- Around line 79-91: Extend the tests to also assert the overlay element's class
when zIndex changes: after calling makeSut (using makeSut and zIndex: "top")
query for the overlay node (e.g., via getByTestId if FloatingOverlay renders a
test id, or by querying document.body for the portal/overlay element) and add an
expectation that its className contains modal.classnames.overlay.base for the
default case and modal.classnames.overlay.top when zIndex is "top"; locate
references to makeSut, modal.classnames.container, modal.classnames.overlay,
zIndex and FloatingOverlay in the spec to implement the additional assertions.

In `@packages/react/src/composite/Modal/src/modal.stories.tsx`:
- Around line 255-292: The story modalOverSidebar mistakenly shares the same
open state for both Sidebar and Modal via useArgs and updateArgs, causing them
to open together; change the Sidebar to have independent state (e.g., set
Sidebar open always true or manage it with its own useState) while keeping the
modal controlled by useArgs/updateArgs (handleClose and open) so the modal can
be shown above an already-open sidebar; update references to Sidebar and Modal
in modalOverSidebar accordingly and ensure only Modal uses the args-provided
open/onDismiss.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: dcf0dbd5-7ad2-44f5-a5e4-ee119b3aa8e9

📥 Commits

Reviewing files that changed from the base of the PR and between 494d9f6 and a952ed2.

⛔ Files ignored due to path filters (2)
  • .yarn/versions/65f6cf1a.yml is excluded by !**/.yarn/**
  • packages/react/src/composite/Modal/src/modal.docs.json is excluded by !**/*.docs.json
📒 Files selected for processing (10)
  • .claude/settings.json
  • packages/core/styles/src/packages/composite/modal/nimbus-modal.css.ts
  • packages/core/styles/src/properties/css.ts
  • packages/core/styles/src/themes/contract.css.ts
  • packages/core/styles/src/themes/globals.css.ts
  • packages/core/tokens/src/zIndex/sys.json
  • packages/react/src/composite/Modal/src/Modal.tsx
  • packages/react/src/composite/Modal/src/modal.spec.tsx
  • packages/react/src/composite/Modal/src/modal.stories.tsx
  • packages/react/src/composite/Modal/src/modal.types.ts

Comment thread .claude/settings.json
Comment thread packages/core/styles/src/packages/composite/modal/nimbus-modal.css.ts Outdated
Comment thread packages/react/src/composite/Modal/src/modal.spec.tsx
Comment thread packages/react/src/composite/Modal/src/modal.stories.tsx
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
packages/react/src/composite/Modal/src/modal.spec.tsx (1)

79-97: ⚠️ Potential issue | 🟠 Major

Add overlay z-index assertions (portal and scoped root) to complete feature coverage.

Current tests validate only containerZIndex. The feature also applies z-index variants to overlays in Modal.tsx (Line 130 and Line 147), so overlay regressions would pass unnoticed.

✅ Suggested test additions
   describe("WHEN zIndex selects a stacking layer", () => {
@@
     it("AND applies the top containerZIndex class when zIndex='top'", () => {
       makeSut({ children: <div>content</div>, zIndex: "top" });
       const modalElement = screen.getByTestId("modal-element");
       expect(modalElement.className).toContain(modal.classnames.container);
       expect(modalElement.className).toContain(
         modal.classnames.containerZIndex.top
       );
     });
+
+    it("AND applies the top overlayZIndex class in portal mode", () => {
+      makeSut({ children: <div>content</div>, zIndex: "top" });
+      const overlay = document.querySelector(`.${modal.classnames.overlay}`);
+      expect(overlay?.className).toContain(modal.classnames.overlayZIndex.top);
+    });
+
+    it("AND applies the top overlayScopedZIndex class in scoped mode", () => {
+      const root = document.createElement("div");
+      document.body.appendChild(root);
+      makeSut({ children: <div>content</div>, zIndex: "top", root });
+      const scopedOverlay = root.querySelector(
+        `.${modal.classnames.overlayScoped}`
+      );
+      expect(scopedOverlay?.className).toContain(
+        modal.classnames.overlayScopedZIndex.top
+      );
+    });
   });

As per coding guidelines, **/*.spec.tsx: Write Jest unit tests for all components testing all component states, accessibility features, and edge cases.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react/src/composite/Modal/src/modal.spec.tsx` around lines 79 - 97,
The tests currently only assert container z-index classes; add assertions that
the overlay elements (both the portal overlay and the scoped-root overlay
rendered by makeSut) also include the overlay base/top classes: check that each
overlay element contains modal.classnames.overlay and the appropriate
modal.classnames.overlayZIndex.base (for default) or
modal.classnames.overlayZIndex.top (when calling makeSut with zIndex: "top");
reuse makeSut to render the modal and query the overlay nodes (by the same test
render output or DOM queries used in other tests) and assert their className
contains those modal.classnames values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/react/src/composite/Modal/src/modal.spec.tsx`:
- Around line 79-97: The tests currently only assert container z-index classes;
add assertions that the overlay elements (both the portal overlay and the
scoped-root overlay rendered by makeSut) also include the overlay base/top
classes: check that each overlay element contains modal.classnames.overlay and
the appropriate modal.classnames.overlayZIndex.base (for default) or
modal.classnames.overlayZIndex.top (when calling makeSut with zIndex: "top");
reuse makeSut to render the modal and query the overlay nodes (by the same test
render output or DOM queries used in other tests) and assert their className
contains those modal.classnames values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0151196e-211b-42de-9a12-4c826f461dd4

📥 Commits

Reviewing files that changed from the base of the PR and between a952ed2 and 3c5575b.

⛔ Files ignored due to path filters (1)
  • .gitignore is excluded by !**/.gitignore
📒 Files selected for processing (4)
  • .coderabbit.yaml
  • packages/core/styles/src/packages/composite/modal/nimbus-modal.css.ts
  • packages/react/src/composite/Modal/src/Modal.tsx
  • packages/react/src/composite/Modal/src/modal.spec.tsx
💤 Files with no reviewable changes (1)
  • .coderabbit.yaml

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 24, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.08%. Comparing base (494d9f6) to head (2d78aef).
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #460   +/-   ##
=======================================
  Coverage   96.07%   96.08%           
=======================================
  Files         426      426           
  Lines        4283     4288    +5     
  Branches      922      908   -14     
=======================================
+ Hits         4115     4120    +5     
- Misses        159      166    +7     
+ Partials        9        2    -7     

☔ View full report in Codecov by Sentry.
📢 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.

@github-actions
Copy link
Copy Markdown
Contributor

🚀✨ Your Storybook preview is ready!

🔗 View Storybook

Happy reviewing! 🎉

@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/publish-rc.yml:
- Around line 50-55: The workflow is using actions/setup-node@v4 with an invalid
input auth-oidc and a Node.js version too old for OIDC Trusted Publishing;
remove the auth-oidc: true line from the setup step (the action ignores that
input) and bump node-version from '20' to a supported OIDC runtime (e.g., '22'
or '22.14.0'+) in the same setup block; ensure the existing explicit
NODE_AUTH_TOKEN: "" environment entry remains unchanged (required for OIDC) and
leave the yarn OIDC-related config (clearing npmAuthIdent and disabling
npmAlwaysAuth) as-is.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 04574014-47a2-4114-973b-50919e96af55

📥 Commits

Reviewing files that changed from the base of the PR and between 3c5575b and 2d78aef.

📒 Files selected for processing (1)
  • .github/workflows/publish-rc.yml

Comment thread .github/workflows/publish-rc.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants