Skip to content

Commit a967102

Browse files
git-nandorclaude
andcommitted
feat(ui-modal): on larger screens, inset the fullscreen modal from the viewport edge for a11y
A size="fullscreen" Modal previously covered the entire viewport edge-to-edge, making it hard to tell it was a modal. On viewports >= md it is now inset via the new fullScreenMargin token, with rounded corners and box-shadow restored. Also compute the box-shadow CSS string once per generateStyle call and reuse it at both usage sites instead of recomputing it on every render. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent f657de6 commit a967102

3 files changed

Lines changed: 22 additions & 6 deletions

File tree

docs/upgrading/upgrade-guide.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,7 @@ type: embed
962962
added={[
963963
{name:"borderWidth",note:""},
964964
{name:"inverseBorderColor",note:""},
965+
{name:"fullScreenMargin",note:""},
965966
]}
966967
changed={[
967968
{oldName:"background",newName:"backgroundColor",note:""},

packages/ui-modal/src/Modal/v2/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ const Example = () => {
148148
background="primary-inverse"
149149
margin="medium auto none"
150150
display="block"
151-
width="25rem"
152-
height="25rem"
151+
width="30rem"
152+
height="30rem"
153153
borderWidth="large"
154154
id="constrainExample"
155155
></View>
@@ -464,6 +464,9 @@ const Example = () => {
464464
<Modal
465465
open={open}
466466
size={smallViewport ? 'fullscreen' : 'small'}
467+
// Simulate real small-screen behavior by themeOverride.
468+
// On actual small screens this happens automatically, so no theme override is needed.
469+
themeOverride={smallViewport ? { fullScreenMargin: '0', borderRadius: '0' } : undefined}
467470
onDismiss={(event) => {
468471
if (event.target.id !== 'toggleViewportButton') {
469472
setOpen(false)

packages/ui-modal/src/Modal/v2/styles.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
*/
2424

2525
import { boxShadowObjectsToCSSString } from '@instructure/ui-themes'
26-
import type { NewComponentTypes } from '@instructure/ui-themes'
26+
import type { NewComponentTypes, SharedTokens } from '@instructure/ui-themes'
2727
import type { ModalProps, ModalStyle } from './props'
2828

2929
/**
@@ -39,9 +39,11 @@ import type { ModalProps, ModalStyle } from './props'
3939
*/
4040
const generateStyle = (
4141
componentTheme: ReturnType<NewComponentTypes['Modal']>,
42-
props: ModalProps
42+
props: ModalProps,
43+
sharedTokens: SharedTokens
4344
): ModalStyle => {
4445
const { size, variant, overflow } = props
46+
const boxShadow = boxShadowObjectsToCSSString(componentTheme.boxShadow)
4547

4648
const commonSizeStyleExceptForFullscreen = {
4749
maxWidth: '95%',
@@ -75,7 +77,17 @@ const generateStyle = (
7577
height: '100%',
7678
boxShadow: 'none',
7779
border: 'none',
78-
borderRadius: 0
80+
borderRadius: 0,
81+
// On larger screens, inset the fullscreen modal from the viewport edge
82+
// for a11y: the Mask flex-centers it, so `flex: 1` + `alignSelf: stretch`
83+
// (auto height) gap it evenly via the margin; corners/shadow restored too.
84+
[`@media screen and (min-width: ${sharedTokens.breakpoints.md})`]: {
85+
margin: componentTheme.fullScreenMargin,
86+
height: 'auto',
87+
alignSelf: 'stretch',
88+
borderRadius: componentTheme.borderRadius,
89+
boxShadow
90+
}
7991
}
8092
}
8193
const backgroundStyles =
@@ -100,7 +112,7 @@ const generateStyle = (
100112
flexDirection: 'column',
101113
position: 'relative',
102114
boxSizing: 'border-box',
103-
boxShadow: boxShadowObjectsToCSSString(componentTheme.boxShadow),
115+
boxShadow,
104116
borderRadius: componentTheme.borderRadius,
105117
overflow: 'hidden',
106118
...sizeStyles[size!],

0 commit comments

Comments
 (0)