Modal: Render as a bottom sheet on mobile#77956
Modal: Render as a bottom sheet on mobile#77956crisbusquets wants to merge 1 commit intoWordPress:trunkfrom
Conversation
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
| // On smaller screens, render as a bottom sheet: edge-to-edge, anchored to | ||
| // the bottom of the viewport, with a height that adapts to the content | ||
| // (capped so it never covers the full viewport). | ||
| margin: auto 0 0 0; |
There was a problem hiding this comment.
Could we use align-self: flex-end here instead of auto margin?
| // On smaller screens, render as a bottom sheet: edge-to-edge, anchored to | |
| // the bottom of the viewport, with a height that adapts to the content | |
| // (capped so it never covers the full viewport). | |
| margin: auto 0 0 0; | |
| // On smaller screens, render as a bottom sheet: edge-to-edge, anchored | |
| // to the bottom of the viewport. `align-self: flex-end` both anchors | |
| // the modal to the bottom of the flex overlay and breaks the default | |
| // `align-items: stretch`, so the modal hugs its content height. | |
| align-self: flex-end; | |
| margin: 0; |
| max-height: none; | ||
| border-radius: 0; | ||
| } | ||
|
|
||
| // Show a centered modal on bigger screens. | ||
| @include break-small() { | ||
| border-radius: $radius-large; | ||
| margin: auto; |
There was a problem hiding this comment.
If we go with the previous suggestion, we may have to also add align-self: auto; here
| // Show a centered modal on bigger screens. | ||
| @include break-small() { | ||
| border-radius: $radius-large; | ||
| margin: auto; | ||
| width: auto; | ||
| min-width: var(--wpds-dimension-surface-width-sm); | ||
| min-width: $modal-min-width; | ||
| max-width: calc(100% - #{$grid-unit-20 * 2}); | ||
| max-height: calc(100% - #{$header-height * 2}); | ||
|
|
||
| &.is-full-screen { | ||
| @include break-small() { |
There was a problem hiding this comment.
Nit (and not introduced by this PR): it looks like the @include break-small() { here is superflous, since this whole CSS block is already nested in a @include break-small() { block a few lines above?
We could take this opportunity to clean this code up a little
Below the `break-small` breakpoint, the Modal now anchors to the bottom of the viewport, adapts its height to the content (capped so the overlay stays visible above), and slides up instead of scaling in. This keeps primary CTAs within thumb reach on touch devices. Behavior at and above `break-small` is unchanged. `is-full-screen` still covers the full viewport on mobile and remains centered with rounded corners on desktop. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
be34b94 to
97d81b4
Compare
@ciampo Fixed! I'll review your other suggestions shortly. Thanks for reviewing it. |


What?
Below the
break-small(600px) breakpoint, theModalcomponent now renders as a bottom sheet:Behavior at and above
break-smallis unchanged.Why?
On the previous mobile layout the modal was anchored to the top with a 40px gap and stretched to fill the remaining viewport height regardless of content.
Two consequences:
A bottom-sheet pattern fixes both: the modal hugs its content and CTAs land in the comfortable thumb zone.
Screenshots
How?
Pure CSS change in
packages/components/src/modal/style.scss:margin: $grid-unit-50 0 0 0withmargin: auto 0 0 0so the modal is pushed to the bottom by the auto top margin (in the existingdisplay: flexoverlay).max-height: calc(100% - $grid-unit-50)so very tall content scrolls inside the sheet rather than covering the overlay.&.is-full-screenmobile rule soisFullScreenmodals continue to cover the entire viewport (margin/border-radius zeroed, width/height 100%).The desktop
&.is-full-screenrule was extended to reset those overrides back tomargin: autoandborder-radius: $radius-large.components-modal__appear-animation/components-modal__disappear-animationkeyframes to slide (translateY(100%) ↔ 0) bydefault, and re-defined them inside
@include break-small()to keep the original scale animation on desktop. The keyframe names are unchanged souse-modal-exit-animation.ts'sanimationendlistener keeps working without JS changes.Testing instructions
npm run storybook:devtop corners only.
isFullScreenon:break-mediumbreakpoint).Types of changes
Bug fix — restores expected mobile UX without changing the public API.
Checklist