Skip to content

Commit eb2ab13

Browse files
joshblackdgreif
andauthored
Trigger onClose when Dialog backdrop is clicked (#4613)
* Trigger onClose when Dialog backdrop is clicked * Update docs with new backdrop gesture * refactor: re-use escape gesture for backdrop click * chore: update changeset * docs: update jsdoc for handler * chore: run format * test: update test to call for escape instead of backdrop --------- Co-authored-by: Dusty Greif <[email protected]> Co-authored-by: Josh Black <[email protected]>
1 parent f252337 commit eb2ab13

File tree

3 files changed

+34
-6
lines changed

3 files changed

+34
-6
lines changed

.changeset/popular-jokes-kiss.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/react': minor
3+
---
4+
5+
`Dialog` and `ConfirmationDialog` can now be closed by clicking on the backdrop surrounding the dialog. This will cause `onClose` to be called with the `escape` gesture.

packages/react/src/Dialog/Dialog.test.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,22 @@ describe('Dialog', () => {
6767

6868
await user.click(getByLabelText('Close'))
6969

70-
expect(onClose).toHaveBeenCalled()
70+
expect(onClose).toHaveBeenCalledWith('close-button')
71+
expect(onClose).toHaveBeenCalledTimes(1) // Ensure it's not called with a backdrop gesture as well
72+
})
73+
74+
it('calls `onClose` when clicking the backdrop', async () => {
75+
const user = userEvent.setup()
76+
const onClose = jest.fn()
77+
const {getByRole} = render(<Dialog onClose={onClose}>Pay attention to me</Dialog>)
78+
79+
expect(onClose).not.toHaveBeenCalled()
80+
81+
const dialog = getByRole('dialog')
82+
const backdrop = dialog.parentElement!
83+
await user.click(backdrop)
84+
85+
expect(onClose).toHaveBeenCalledWith('escape')
7186
})
7287

7388
it('calls `onClose` when keying "Escape"', async () => {
@@ -80,7 +95,7 @@ describe('Dialog', () => {
8095

8196
await user.keyboard('{Escape}')
8297

83-
expect(onClose).toHaveBeenCalled()
98+
expect(onClose).toHaveBeenCalledWith('escape')
8499
})
85100

86101
it('changes the <body> style for `overflow` if it is not set to "hidden"', () => {

packages/react/src/Dialog/Dialog.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useCallback, useEffect, useRef, useState} from 'react'
1+
import React, {useCallback, useEffect, useRef, useState, type SyntheticEvent} from 'react'
22
import styled from 'styled-components'
33
import type {ButtonProps} from '../Button'
44
import {Button} from '../Button'
@@ -98,9 +98,9 @@ export interface DialogProps extends SxProp {
9898

9999
/**
100100
* This method is invoked when a gesture to close the dialog is used (either
101-
* an Escape key press or clicking the "X" in the top-right corner). The
101+
* an Escape key press, clicking the backdrop, or clicking the "X" in the top-right corner). The
102102
* gesture argument indicates the gesture that was used to close the dialog
103-
* (either 'close-button' or 'escape').
103+
* ('close-button' or 'escape').
104104
*/
105105
onClose: (gesture: 'close-button' | 'escape') => void
106106

@@ -414,6 +414,14 @@ const _Dialog = React.forwardRef<HTMLDivElement, React.PropsWithChildren<DialogP
414414
}
415415
}
416416
const defaultedProps = {...props, title, subtitle, role, dialogLabelId, dialogDescriptionId}
417+
const onBackdropClick = useCallback(
418+
(e: SyntheticEvent) => {
419+
if (e.target === e.currentTarget) {
420+
onClose('escape')
421+
}
422+
},
423+
[onClose],
424+
)
417425

418426
const dialogRef = useRef<HTMLDivElement>(null)
419427
useRefObjectAsForwardedRef(forwardedRef, dialogRef)
@@ -465,7 +473,7 @@ const _Dialog = React.forwardRef<HTMLDivElement, React.PropsWithChildren<DialogP
465473
return (
466474
<>
467475
<Portal>
468-
<Backdrop ref={backdropRef} {...positionDataAttributes}>
476+
<Backdrop ref={backdropRef} {...positionDataAttributes} onClick={onBackdropClick}>
469477
<StyledDialog
470478
width={width}
471479
height={height}

0 commit comments

Comments
 (0)