Skip to content

feat: Update Sana Canvas Popup, Modal and Dialog#4018

Open
josh-bagwell wants to merge 10 commits into
Workday:prerelease/majorfrom
josh-bagwell:feat/update-sana-canvas-popup-dialog-modal-26-06
Open

feat: Update Sana Canvas Popup, Modal and Dialog#4018
josh-bagwell wants to merge 10 commits into
Workday:prerelease/majorfrom
josh-bagwell:feat/update-sana-canvas-popup-dialog-modal-26-06

Conversation

@josh-bagwell

@josh-bagwell josh-bagwell commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes: #3988

Release Category

Components

Release Note

Updates Popup, Modal and Dialog to new Sana Canvas styling.

BREAKING CHANGES

Visual.


Where Should the Reviewer Start?

/modules/react/dialog
/modules/react/modal
/modules/react/popup

Summary by CodeRabbit

  • New Features
    • Added Dialog.ButtonGroup, Modal.ButtonGroup, and Popup.ButtonGroup for consistent grouped action-button layouts, including alignment options for popups.
  • Style
    • Updated dialog, modal, and popup examples to use button groups instead of flex-based spacing, with standardized button ordering (e.g., “Cancel” first).
    • Refreshed popup card padding, adjusted toast close-icon positioning, and updated combobox card styling.
  • Documentation
    • Updated tooltip documentation to support inline-block body styling.
  • Tests
    • Updated Cypress focus/tab-order assertions for modal and popup scenarios to match the new button-group layout.

@josh-bagwell josh-bagwell self-assigned this Jun 24, 2026
@josh-bagwell
josh-bagwell requested a review from a team as a code owner June 24, 2026 17:48
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds a shared Popup.ButtonGroup component and exposes it as Popup.ButtonGroup, Modal.ButtonGroup, and Dialog.ButtonGroup. Popup, modal, and dialog examples migrate from Flex wrappers, with updated action ordering and focus expectations.

Changes

ButtonGroup subcomponent and story migration

Layer / File(s) Summary
PopupButtonGroup implementation
modules/react/popup/lib/PopupButtonGroup.tsx
Defines typed props, responsive flex styling, button positioning, growth behavior, and popup-model integration.
Container API wiring
modules/react/popup/lib/Popup.tsx, modules/react/modal/lib/Modal.tsx, modules/react/dialog/lib/Dialog.tsx, modules/react/popup/lib/PopupCard.tsx
Registers the shared button group on Popup, Modal, and Dialog, and updates popup card padding tokens.
Popup examples and focus validation
modules/react/popup/stories/examples/*.tsx, cypress/component/Popup.spec.tsx
Replaces popup Flex action wrappers with Popup.ButtonGroup, preserves handlers and refs, changes button order, and updates focus-test setup.
Modal examples and focus validation
modules/react/modal/stories/examples/*.tsx, cypress/component/Modal.spec.tsx
Replaces modal Flex action wrappers with Modal.ButtonGroup, updates nested popup and tooltip layouts, adjusts form growth props, and changes tab-order expectations.
Dialog examples and ordering
modules/react/dialog/stories/examples/*.tsx, modules/react/dialog/stories/FallbackTesting.stories.tsx
Replaces dialog Flex wrappers with Dialog.ButtonGroup, adds input growth props, and renders Cancel before Submit or the primary action.
Related component and documentation updates
modules/react/combobox/lib/ComboboxCard.tsx, modules/react/select/stories/examples/Basic.tsx, modules/react/toast/lib/ToastCloseIcon.tsx, modules/react/tooltip/stories/Tooltip.mdx
Removes the ComboboxCard stencil, adds a Select growth prop, switches toast positioning to tokens, and applies inline display styling in tooltip documentation.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Possibly related issues

  • #3975 — Updates Popup, Dialog, and Modal button-group APIs and related examples.

Suggested labels: needs-a11y

Suggested reviewers: mannycarrera4, rayredgoose, williamjstanton

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Dialog and Modal ButtonGroup and story ordering work are present, but the required token updates and migration guidance/codemod are not shown. Add the v16 token/style updates for Dialog and Modal, include migration guidance or a codemod for the footer-order change, and verify RTL ordering.
Out of Scope Changes check ⚠️ Warning The PR also changes Popup, Combobox, Toast, Tooltip, and Cypress tests, which are outside #3988's Dialog/Modal scope. Split unrelated Popup, Combobox, Toast, and Tooltip changes into separate PRs unless they are required for the Dialog/Modal implementation.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the main dialog and modal styling update.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@josh-bagwell josh-bagwell changed the title Feat/update sana canvas popup dialog modal 26 06 feat: Update Popup, Modal and Dialog Sana Canvas Jun 24, 2026
@josh-bagwell josh-bagwell changed the title feat: Update Popup, Modal and Dialog Sana Canvas feat: Update Sana Canvas Popup, Modal and Dialog Jun 24, 2026
@cypress

cypress Bot commented Jun 24, 2026

Copy link
Copy Markdown

Workday/canvas-kit    Run #11297

Run Properties:  status check passed Passed #11297  •  git commit b60321d596 ℹ️: Merge 15c85a4a7bdaa09837a104519d5ff05280518d02 into e91ae68242623c9e4d24b9fbdc3c...
Project Workday/canvas-kit
Branch Review feat/update-sana-canvas-popup-dialog-modal-26-06
Run status status check passed Passed #11297
Run duration 02m 29s
Commit git commit b60321d596 ℹ️: Merge 15c85a4a7bdaa09837a104519d5ff05280518d02 into e91ae68242623c9e4d24b9fbdc3c...
Committer Josh
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 17
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 809
View all changes introduced in this branch ↗︎
UI Coverage  19.65%
  Untested elements 1523  
  Tested elements 370  
Accessibility  99.47%
  Failed rules  5 critical   5 serious   0 moderate   2 minor
  Failed elements 72  

@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.

Actionable comments posted: 4

🧹 Nitpick comments (1)
modules/react/popup/lib/PopupButtonGroup.tsx (1)

41-47: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

grow selector matches all descendant buttons.

& button is a descendant combinator, so when a ButtonGroup contains nested interactive content (e.g. the nested Popup/Modal patterns in ModalWithPopup/WithTooltips), enabling grow would also force-width any deeper button elements. Consider scoping to direct children (& > button) if only the group's own buttons should grow.

♻️ Optional scoping
     grow: {
       true: {
-        '& button': {
+        '& > button': {
           width: '100%',
         },
       },
     },
🤖 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 `@modules/react/popup/lib/PopupButtonGroup.tsx` around lines 41 - 47, The
`grow` style in `PopupButtonGroup` is too broad because `& button` targets all
descendant buttons, including nested buttons inside popup/modal content. Update
the `grow.true` rule in `PopupButtonGroup.tsx` to scope the width styling to the
group’s direct button children only, using the relevant selector in the `grow`
block so nested interactive content is unaffected.
🤖 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.

Inline comments:
In `@modules/react/modal/lib/Modal.tsx`:
- Around line 95-99: The JSDoc for `Modal.ButtonGroup` contains a broken symbol
reference: it points to `modalButtonGroupStencil`, which does not exist, and the
linked `ButtonGroup` reference should also be aligned with the actual
implementation. Update the documentation in `Modal.ButtonGroup` to reference the
existing `popupButtonGroupStencil` used by `Popup.ButtonGroup`, and fix the
corresponding broken `{`@link` ButtonGroup}` reference in `Popup.tsx` so the docs
resolve correctly.

In `@modules/react/modal/stories/examples/ModalWithPopup.tsx`:
- Around line 34-37: The Cancel action inside ModalWithPopup is currently using
Popup.CloseButton, so it only targets the nested popup instead of dismissing the
surrounding modal. Update the button in the ModalWithPopup story to use the
modal’s close/dismiss control (or wire it through the modal’s close handler) and
keep the popup-specific controls only for Popup.ButtonGroup, Popup.CloseButton,
and Popup.Target where they actually manage the popup state.

In `@modules/react/modal/stories/examples/ModalWithPopupRTL.tsx`:
- Around line 35-38: The first visible “Cancel” action in the RTL modal is still
wired to Popup.CloseButton, so it only targets the popup instead of dismissing
the modal. Update the ModalWithPopupRTL story to bind that outer Cancel control
to the modal’s close action (using the modal component’s close/dismiss wiring)
while keeping the popup-specific controls inside Popup.ButtonGroup unchanged.
Use the existing Popup and modal button setup in ModalWithPopupRTL to locate the
affected JSX and switch the Cancel button to the modal-level handler.

In `@modules/react/popup/lib/Popup.tsx`:
- Around line 115-119: The JSDoc for Popup.ButtonGroup incorrectly links to a
non-existent ButtonGroup symbol and should describe PopupButtonGroup as its own
standalone component instead. Update the doc text on PopupButtonGroup in
Popup.tsx to remove the broken {`@link` ButtonGroup} reference while keeping the
valid {`@link` popupButtonGroupStencil} link, and apply the same wording fix to
the duplicated documentation in Dialog.tsx and Modal.tsx.

---

Nitpick comments:
In `@modules/react/popup/lib/PopupButtonGroup.tsx`:
- Around line 41-47: The `grow` style in `PopupButtonGroup` is too broad because
`& button` targets all descendant buttons, including nested buttons inside
popup/modal content. Update the `grow.true` rule in `PopupButtonGroup.tsx` to
scope the width styling to the group’s direct button children only, using the
relevant selector in the `grow` block so nested interactive content is
unaffected.
🪄 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: CHILL

Plan: Pro Plus

Run ID: b46e66e1-4b71-425e-9951-674d7ee0b1d1

📥 Commits

Reviewing files that changed from the base of the PR and between d6ad8e0 and 12a9733.

📒 Files selected for processing (31)
  • modules/react/dialog/lib/Dialog.tsx
  • modules/react/dialog/stories/FallbackTesting.stories.tsx
  • modules/react/dialog/stories/examples/Basic.tsx
  • modules/react/dialog/stories/examples/DialogWithFallbackPlacements.tsx
  • modules/react/dialog/stories/examples/Focus.tsx
  • modules/react/modal/lib/Modal.tsx
  • modules/react/modal/stories/examples/Basic.tsx
  • modules/react/modal/stories/examples/BodyOverflow.tsx
  • modules/react/modal/stories/examples/CustomFocus.tsx
  • modules/react/modal/stories/examples/FormModal.tsx
  • modules/react/modal/stories/examples/FullOverflow.tsx
  • modules/react/modal/stories/examples/IframeTest.tsx
  • modules/react/modal/stories/examples/ModalWithPopup.tsx
  • modules/react/modal/stories/examples/ModalWithPopupRTL.tsx
  • modules/react/modal/stories/examples/NoTargetRTL.tsx
  • modules/react/modal/stories/examples/ReturnFocus.tsx
  • modules/react/modal/stories/examples/StackedModals.tsx
  • modules/react/modal/stories/examples/WithTooltips.tsx
  • modules/react/modal/stories/examples/WithoutCloseIcon.tsx
  • modules/react/popup/lib/Popup.tsx
  • modules/react/popup/lib/PopupButtonGroup.tsx
  • modules/react/popup/lib/PopupCard.tsx
  • modules/react/popup/stories/examples/Basic.tsx
  • modules/react/popup/stories/examples/FocusRedirect.tsx
  • modules/react/popup/stories/examples/FocusTrap.tsx
  • modules/react/popup/stories/examples/InitialFocus.tsx
  • modules/react/popup/stories/examples/InlinePopup.tsx
  • modules/react/popup/stories/examples/MultiplePopups.tsx
  • modules/react/popup/stories/examples/NestedPopups.tsx
  • modules/react/popup/stories/examples/PopupWithFallbackPlacements.tsx
  • modules/react/popup/stories/examples/RTL.tsx

Comment thread modules/react/modal/lib/Modal.tsx
Comment thread modules/react/modal/stories/examples/ModalWithPopup.tsx
Comment thread modules/react/modal/stories/examples/ModalWithPopupRTL.tsx
Comment thread modules/react/popup/lib/Popup.tsx
@josh-bagwell josh-bagwell added ready for review Code is ready for review needs-a11y Extra attention from accessibility is needed labels Jun 25, 2026

@williamjstanton williamjstanton left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Possible omissions on the upgrade guide? Can we double check on these?

Low: The v16 upgrade guide does not mention the new Popup/Dialog/Modal.ButtonGroup public API or the Popup.Card padding change.

Otherwise, looking good on accessibility side so far.

},
});

export const PopupButtonGroup = createSubcomponent('div')({

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Medium: Popup.ButtonGroup is documented in JSDoc as a button “group,” but it renders a layout-only div with no group semantics. That may be fine for dialog action rows, but it conflicts with existing Button docs that recommend semantic grouping via ul or fieldset/legend for related buttons. Recommend documenting *.ButtonGroup as visual/layout-only, and showing when to add role="group" plus an accessible name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I can update this. Thanks WIlliam!

@josh-bagwell josh-bagwell Jun 27, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

When would be a good time to add a role="group" to the group?

Thoughts on the accessible name being "Actions" (i.e. aria-label="Actions").

@williamjstanton williamjstanton Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

When would be a good time to add a role="group" to the group?

Thoughts on the accessible name being "Actions" (i.e. aria-label="Actions").

It's a good question. As mentioned already, it's fine without in most situations of a dialog with 2 actions. The aria-label string is always going to be contextual based on the design situation.

I probably should spend some research time brainstorming situations where programmatic grouping is valuable and contribute examples separately. The classic example is always a form that requires you to fill out both a Shipping address and a Billing address. (Fields must necessarily have identical labels, with different group contexts. )

boxShadow: system.depth[3],
minHeight: 0,
padding: system.legacy.padding.xl,
padding: system.legacy.padding.xxl,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I’d still recommend adding or running a 320px viewport visual/accessibility check because Popup.Card padding increased to xxl, reducing usable content width.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Let me take a look.

@@ -198,7 +198,7 @@ describe('Popup', () => {
// useFocusRedirect hides on Tab only from the last focusable in the popup (Close, Delete, Cancel)
context('when the "Cancel" button has focus and the tab key is pressed', () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Low: The focus redirect Cypress description/comment is now stale: it says the Cancel button has focus and lists order as Close, Delete, Cancel, but the test focuses Delete after the PR’s reordered DOM. That weakens the accessibility spec around focus order.

@RayRedGoose

Copy link
Copy Markdown
Contributor

Do we have padding changed? It looks different in visual tests. We also need to setup sana theme in tests.
Also do we have info how button group should behave on small width modals? just align to right can look odd
Screenshot 2026-06-26 at 4 01 08 PM

@josh-bagwell

Copy link
Copy Markdown
Contributor Author

Do we have padding changed? It looks different in visual tests. We also need to setup sana theme in tests. Also do we have info how button group should behave on small width modals? just align to right can look odd Screenshot 2026-06-26 at 4 01 08 PM

We don't have specific info on smaller sizes but, I have it set to stacking:
Screenshot 2026-06-26 at 5 58 43 PM

@RayRedGoose

Copy link
Copy Markdown
Contributor

Overall PR looks good, but I think we will need to finalize our tokens change strategy before. This PR can request additional changes to how to add theme (if we finally decide to use that for v16) to popups, so Sana styles are consumed by popups.

@RayRedGoose RayRedGoose added approved Code has been reviewed and approved (ship it) and removed ready for review Code is ready for review needs-a11y Extra attention from accessibility is needed labels Jul 9, 2026
@RayRedGoose RayRedGoose linked an issue Jul 9, 2026 that may be closed by this pull request
9 tasks

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.

nit: Good to remove the unused Flex import?

Comment thread cypress/component/Popup.spec.tsx Outdated
@@ -198,7 +198,7 @@ describe('Popup', () => {
// useFocusRedirect hides on Tab only from the last focusable in the popup (Close, Delete, Cancel)

@sheelah sheelah Jul 9, 2026

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.

nit: Do we want to update this comment and the test description below now that the "Delete" button is the last focusable element?

import {TextInput} from '@workday/canvas-kit-react/text-input';
import {system} from '@workday/canvas-tokens-web';

export const CustomFocus = () => {

@sheelah sheelah Jul 9, 2026

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.

Looks like the alignment of the text input and buttons is off now vs v15. I assume we want the buttons and text input's ends to align vertically? Something to confirm with design.

Image

v15:

Image

padding: system.padding.xs,
});

export const FormModal = () => {

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.

Seeing the same alignment issue in this form + the buttons as well:

Image

<p>Are you sure you want to delete the item?</p>
<Flex cs={{gap: system.gap.md}}>
<Modal.CloseButton as={DeleteButton}>Delete</Modal.CloseButton>
<Modal.ButtonGroup>

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.

Same alignment question for this story:

Image

},
},
});

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.

this was causing an aggressive border radius which we no longer need

Caution: Describe type has been deprecated{' '}
</InformationHighlight.Heading>
<InformationHighlight.Body>
<InformationHighlight.Body cs={{'p': {display: 'inline-block'}}}>

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.

aligns the status indicators nicely in storybook

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Code has been reviewed and approved (ship it)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Sana Canvas Popup, Dialog & Modal

5 participants