Skip to content

fix(styles): introduce modal max-height#2249

Open
gupta-tanvi26 wants to merge 5 commits intodevelopfrom
fix/introduce-modal-max-height
Open

fix(styles): introduce modal max-height#2249
gupta-tanvi26 wants to merge 5 commits intodevelopfrom
fix/introduce-modal-max-height

Conversation

@gupta-tanvi26
Copy link

@gupta-tanvi26 gupta-tanvi26 commented Feb 13, 2026

2249.mov

This PR fixes situations when the length of the modal content exceeds the viewport. In case of modal content overflowing on large viewports, we want the modal content to be scrollable while the footer buttons stay fixed at the bottom of the screen, above the fold. On small viewports, the footer buttons can go below the fold of the screen and we should be able to scroll through the entire modal and not just the modal content.

The following are the breakpoints we follow -

@Viewport:320px (20rem)
@Viewport:768px (48rem)
@Viewport:1280px (64rem)

We want anything above 320px to have scrollable modal content.

Closes #2125

@aws-amplify-us-east-1
Copy link

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-2249.d15792l1n26ww3.amplifyapp.com

@gupta-tanvi26 gupta-tanvi26 marked this pull request as ready for review February 13, 2026 20:13
@gupta-tanvi26 gupta-tanvi26 requested review from a team as code owners February 13, 2026 20:13
Copilot AI review requested due to automatic review settings February 13, 2026 20:13
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses #2125 by constraining dialog/modal height so long modal content can be scrolled instead of pushing footer controls below the fold.

Changes:

  • Add a max-height constraint to .Dialog__inner and overflow-y: auto to .Dialog__content.
  • Add Modal visual-regression coverage via new Playwright screenshot tests and baseline images.
  • Add an accessibility (axe) regression test case for long modal content.

Reviewed changes

Copilot reviewed 3 out of 11 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/styles/dialog.css Adds max-height + scroll behavior for dialog content.
packages/react/src/components/Modal/screenshots.e2e.tsx New Modal screenshot coverage for small/large content across viewports and themes.
packages/react/src/components/Modal/index.test.tsx Adds axe tests intended to cover long-content scenarios.
e2e/screenshots/modal-small-content.png New baseline screenshot.
e2e/screenshots/dark--modal-small-content.png New baseline screenshot (dark theme).
e2e/screenshots/modal-large-content-large-viewport.png New baseline screenshot (large viewport).
e2e/screenshots/modal-large-content-small-viewport.png New baseline screenshot (small viewport).
e2e/screenshots/dark--modal-large-content-small-viewport.png New baseline screenshot (dark + small viewport).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 63 to 102
describe('should return no axe violations when the modal content is long', () => {
afterAll(() => {
Object.defineProperty(window, 'innerWidth', {
writable: true,
configurable: true,
value: 1024
});
window.dispatchEvent(new Event('resize'));
});

test('on small viewport', async () => {
Object.defineProperty(window, 'innerWidth', {
writable: true,
configurable: true,
value: 310
});

window.dispatchEvent(new Event('resize'));

const { container } = render(
<Modal {...defaults} show={true}>
<ModalContent>{createLongContent()}</ModalContent>
<ModalFooter>
<button>Ok</button>
</ModalFooter>
</Modal>
);

expect(await axe(container)).toHaveNoViolations();
});

test('on large viewport', async () => {
Object.defineProperty(window, 'innerWidth', {
writable: true,
configurable: true,
value: 720
});

window.dispatchEvent(new Event('resize'));

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

These tests modify window.innerWidth and dispatch resize, but the Dialog/Modal implementation does not read innerWidth, matchMedia, or listen to resize events (it’s purely CSS-driven). That means this setup doesn’t affect rendering and adds unnecessary complexity/flakiness. Consider removing the innerWidth/resize manipulation (or replacing it with assertions that validate actual DOM/CSS behavior if needed).

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

Made changes - 5c3f845

Comment on lines 162 to 170
@media (min-width: 320px) {
.Dialog__inner {
max-height: calc(100vh - 130px);
}

.Dialog__content {
overflow-y: auto;
}
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The new rules are wrapped in @media (min-width: 320px), which effectively applies to almost all devices and makes the “small viewport” behavior only trigger below 320px. This doesn’t match the PR description/issue note about switching behavior at a meaningful breakpoint (so the whole dialog can scroll on small viewports). Consider using a real breakpoint (e.g. align with the existing 460px modal breakpoint in layout.css) and explicitly setting small-viewport behavior (e.g. make the .Dialog/overlay scrollable and avoid constraining .Dialog__inner).

Copilot uses AI. Check for mistakes.
Copy link
Author

@gupta-tanvi26 gupta-tanvi26 Feb 16, 2026

Choose a reason for hiding this comment

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

As per the design specs - we want the entire modal to be scrollable below 320px

Comment on lines 163 to 166
.Dialog__inner {
max-height: calc(100vh - 130px);
}

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

max-height: calc(100vh - 130px) introduces a hard-coded 130px that isn’t derived from existing dialog variables (e.g., the top: 100px offset, header/footer sizes, padding). This makes the layout fragile if any of those values change. Consider computing this from CSS custom properties (or introducing a --dialog-vertical-offset/--dialog-max-height-offset) so the max-height stays consistent with the dialog’s actual spacing.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

Made changes - 9a32c5c

mount,
page
}) => {
await page.setViewportSize({ width: 319, height: 667 });
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

This test sets the viewport width to 319px, which appears chosen specifically to fall below the new CSS min-width: 320px rule, rather than to represent a real breakpoint. This makes the screenshot coverage brittle and can miss the intended “small viewport” behavior for common device widths (e.g. 360–430px). Consider aligning the viewport size(s) here with the actual breakpoint you choose for the dialog scrolling behavior (and update screenshots accordingly).

Suggested change
await page.setViewportSize({ width: 319, height: 667 });
await page.setViewportSize({ width: 360, height: 667 });

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

As per the design we want the entire modal to be scrollable below 320 px.

Comment on lines 29 to 32
await expect(page).toHaveScreenshot('modal-small-content.png');
await setTheme(page, 'dark');
await expect(page).toHaveScreenshot('dark--modal-small-content.png');
});
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

In this repo’s screenshot tests, toHaveScreenshot is generally called without a file extension (Playwright appends .png), and often targets a specific locator rather than the full page. Using explicit .png names and full-page screenshots here is inconsistent and can increase snapshot churn. Consider switching to a dialog-scoped locator (e.g. page.getByRole('dialog')) and using extension-less screenshot names for consistency with other component screenshot suites.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

Made changes - 5c3f845

Bracciata

This comment was marked as resolved.

shawnsharpDQ
shawnsharpDQ previously approved these changes Feb 16, 2026
Copy link
Contributor

@Zidious Zidious left a comment

Choose a reason for hiding this comment

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

This is looking great! Left some minor comments, also the 🤖 has reasonable comments.

Small nit: we'd want to scope your title to something like fix(react): ... so we can have the changelog generation scope the fix to the correct CHANGELOG file (see conventional commits docs).

@gupta-tanvi26 gupta-tanvi26 changed the title fix: introduce modal max-height fix(styles): introduce modal max-height Feb 18, 2026
shawnsharpDQ
shawnsharpDQ previously approved these changes Feb 18, 2026
Copy link
Contributor

@maksym-shynkarenko maksym-shynkarenko left a comment

Choose a reason for hiding this comment

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

LGTM, but I'm not really familiar with cauldron. Leave the final review on @anastasialanz

@gupta-tanvi26 gupta-tanvi26 dismissed stale reviews from Zidious and Bracciata February 18, 2026 16:59

Addressed!

Zidious
Zidious previously approved these changes Feb 18, 2026
Copy link
Contributor

@Zidious Zidious left a comment

Choose a reason for hiding this comment

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

LGTM - Awesome work ☕ !

expect(await axe(document.body)).toHaveNoViolations();
});

function createLongContent() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit - For these types utility functions, try to have them at the top of the file in the event we need to add future test, like you have for the E2E tests.

Copy link
Author

Choose a reason for hiding this comment

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

Made changes - be1bd51

Bracciata
Bracciata previously approved these changes Feb 18, 2026
Copy link
Contributor

@Bracciata Bracciata left a comment

Choose a reason for hiding this comment

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

Looks good to ship 🚀🚀

chornonoh-vova
chornonoh-vova previously approved these changes Feb 23, 2026
Comment on lines 79 to 87
function createLongContent() {
return (
<>
{Array.from({ length: 50 }, (_, i) => (
<p key={i}>Modal content here, get your modal content here!</p>
))}
</>
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit -
Seems like we use this helper function in several places:
packages/react/src/components/Modal/index.test.tsx
packages/react/src/components/Modal/screenshots.e2e.tsx

it might have sense to move it to some test-util file or similar

Copy link
Author

Choose a reason for hiding this comment

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

Made changes - be1bd51

Copy link
Contributor

@Bracciata Bracciata left a comment

Choose a reason for hiding this comment

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

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.

Introduce modal max-height

8 participants