Fix dialog dismissal in Backstage UI (#33785)

Dismissing a dialog by clicking on the overlay doesn't work currently despite being enabled. This is because what appears to be the overlay in the UI is actually the modal content instead, as the classes are applied incorrectly. This PR fixes that by separating out the overlay from the Modal component and lifting each of the classes up one layer.

---------

Signed-off-by: James Brooks <jamesbrooks@spotify.com>
This commit is contained in:
James Brooks
2026-04-13 11:21:56 +01:00
committed by GitHub
parent 53143805a0
commit 67b88815ae
5 changed files with 33 additions and 14 deletions
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/ui': patch
---
Added `ModalOverlay` to `Dialog` so overlay styles are applied to the actual overlay rather than the modal content, and fixed dismissing via outside click in the process.
**Affected components:** Dialog
+2 -1
View File
@@ -1124,7 +1124,8 @@ export const DialogDefinition: {
};
readonly classNames: {
readonly root: 'bui-DialogOverlay';
readonly dialog: 'bui-Dialog';
readonly container: 'bui-Dialog';
readonly inner: 'bui-DialogInner';
readonly content: 'bui-DialogContent';
};
readonly propDefs: {
@@ -56,6 +56,13 @@
max-width: calc(100vw - 3rem);
height: var(--bui-dialog-height, auto);
max-height: calc(100vh - 3rem);
}
.bui-DialogInner {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
outline: none;
}
+15 -12
View File
@@ -19,6 +19,7 @@ import {
Dialog as RADialog,
DialogTrigger as RADialogTrigger,
Modal,
ModalOverlay,
Heading,
} from 'react-aria-components';
import type {
@@ -58,20 +59,20 @@ export const DialogTrigger = (props: DialogTriggerProps) => {
export const Dialog = forwardRef<React.ElementRef<typeof Modal>, DialogProps>(
(props, ref) => {
const { ownProps, restProps } = useDefinition(DialogDefinition, props, {
classNameTarget: 'dialog',
classNameTarget: 'container',
});
const { classes, children, width, height, style } = ownProps;
return (
<Modal
ref={ref}
<ModalOverlay
className={classes.root}
isDismissable
isKeyboardDismissDisabled={false}
{...restProps}
>
<RADialog
className={classes.dialog}
<Modal
ref={ref}
className={classes.container}
style={{
['--bui-dialog-min-width' as keyof React.CSSProperties]:
typeof width === 'number' ? `${width}px` : width || '400px',
@@ -84,13 +85,15 @@ export const Dialog = forwardRef<React.ElementRef<typeof Modal>, DialogProps>(
...style,
}}
>
<BgReset>
<Box bg="neutral" className={classes.content}>
{children}
</Box>
</BgReset>
</RADialog>
</Modal>
<RADialog className={classes.inner}>
<BgReset>
<Box bg="neutral" className={classes.content}>
{children}
</Box>
</BgReset>
</RADialog>
</Modal>
</ModalOverlay>
);
},
);
@@ -31,7 +31,8 @@ export const DialogDefinition = defineComponent<DialogOwnProps>()({
styles,
classNames: {
root: 'bui-DialogOverlay',
dialog: 'bui-Dialog',
container: 'bui-Dialog',
inner: 'bui-DialogInner',
content: 'bui-DialogContent',
},
propDefs: {