From 67b88815aeb6512b8b9ee734f7c9810321523e17 Mon Sep 17 00:00:00 2001 From: James Brooks <52410024+jabrks@users.noreply.github.com> Date: Mon, 13 Apr 2026 11:21:56 +0100 Subject: [PATCH] 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 --- .changeset/neat-impalas-cross.md | 7 +++++ packages/ui/report.api.md | 3 ++- .../src/components/Dialog/Dialog.module.css | 7 +++++ packages/ui/src/components/Dialog/Dialog.tsx | 27 ++++++++++--------- .../ui/src/components/Dialog/definition.ts | 3 ++- 5 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 .changeset/neat-impalas-cross.md diff --git a/.changeset/neat-impalas-cross.md b/.changeset/neat-impalas-cross.md new file mode 100644 index 0000000000..9910e53e3f --- /dev/null +++ b/.changeset/neat-impalas-cross.md @@ -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 diff --git a/packages/ui/report.api.md b/packages/ui/report.api.md index 181fa48731..877b545bef 100644 --- a/packages/ui/report.api.md +++ b/packages/ui/report.api.md @@ -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: { diff --git a/packages/ui/src/components/Dialog/Dialog.module.css b/packages/ui/src/components/Dialog/Dialog.module.css index 194128ec4d..b6d26b3f3d 100644 --- a/packages/ui/src/components/Dialog/Dialog.module.css +++ b/packages/ui/src/components/Dialog/Dialog.module.css @@ -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; } diff --git a/packages/ui/src/components/Dialog/Dialog.tsx b/packages/ui/src/components/Dialog/Dialog.tsx index 7f421ff783..96355dc3dd 100644 --- a/packages/ui/src/components/Dialog/Dialog.tsx +++ b/packages/ui/src/components/Dialog/Dialog.tsx @@ -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, DialogProps>( (props, ref) => { const { ownProps, restProps } = useDefinition(DialogDefinition, props, { - classNameTarget: 'dialog', + classNameTarget: 'container', }); const { classes, children, width, height, style } = ownProps; return ( - - , DialogProps>( ...style, }} > - - - {children} - - - - + + + + {children} + + + + + ); }, ); diff --git a/packages/ui/src/components/Dialog/definition.ts b/packages/ui/src/components/Dialog/definition.ts index 95463f188e..957b02427d 100644 --- a/packages/ui/src/components/Dialog/definition.ts +++ b/packages/ui/src/components/Dialog/definition.ts @@ -31,7 +31,8 @@ export const DialogDefinition = defineComponent()({ styles, classNames: { root: 'bui-DialogOverlay', - dialog: 'bui-Dialog', + container: 'bui-Dialog', + inner: 'bui-DialogInner', content: 'bui-DialogContent', }, propDefs: {