Skip to content

Commit

Permalink
Add support for initial focus ref to Dialog 2 (#4729)
Browse files Browse the repository at this point in the history
* Add support for initial focus ref to Dialog 2

* add test and docs

* Create seven-phones-talk.md
  • Loading branch information
broccolinisoup authored Jul 15, 2024
1 parent ba253d7 commit 71bdfa8
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/seven-phones-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/react": minor
---

Dialog2: Add support for "InitialFocusRef" that allows to specify an element that should receive focus when the dialog opens.
5 changes: 5 additions & 0 deletions packages/react/src/Dialog/Dialog.docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@
"name": "returnFocusRef",
"type": "React.RefObject<HTMLElement>",
"describedby": "Return focus to this element when the Dialog closes, instead of the element that had focus immediately before the Dialog opened"
},
{
"name": "initialFocusRef",
"type": "React.RefObject<HTMLElement>",
"description": "Focus this element when the Dialog opens"
}
],
"subcomponents": []
Expand Down
28 changes: 27 additions & 1 deletion packages/react/src/Dialog/Dialog.features.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {useState, useRef, useCallback} from 'react'
import {Box, TextInput, Text, Button} from '..'
import {Box, TextInput, Text, Button, ActionList} from '..'
import type {DialogProps, DialogWidth, DialogHeight} from './Dialog'
import {Dialog} from './Dialog'

Expand Down Expand Up @@ -304,3 +304,29 @@ export const ReturnFocusRef = () => {
</React.Suspense>
)
}

export const NewIssues = () => {
const [isOpen, setIsOpen] = useState(false)
const onDialogClose = useCallback(() => setIsOpen(false), [])
const initialFocusRef = useRef(null)
return (
<>
<Button onClick={() => setIsOpen(true)}>Show dialog</Button>
{isOpen ? (
<Dialog
initialFocusRef={initialFocusRef}
onClose={onDialogClose}
title="New issue"
renderBody={() => (
<ActionList>
<ActionList.LinkItem ref={initialFocusRef} href="https://github.com">
Item 1
</ActionList.LinkItem>
<ActionList.LinkItem href="https://github.com">Link</ActionList.LinkItem>
</ActionList>
)}
></Dialog>
) : null}
</>
)
}
18 changes: 18 additions & 0 deletions packages/react/src/Dialog/Dialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,21 @@ describe('Dialog', () => {
expect(getByRole('button', {name: 'return focus to (button 2)'})).toHaveFocus()
})
})

it('automatically focuses the element that is specified as initialFocusRef', () => {
const initialFocusRef = React.createRef<HTMLAnchorElement>()
const {getByRole} = render(
<Dialog
initialFocusRef={initialFocusRef}
onClose={() => {}}
title="New issue"
renderBody={() => (
<a ref={initialFocusRef} href="https://github.com">
Item 1
</a>
)}
></Dialog>,
)

expect(getByRole('link')).toHaveFocus()
})
8 changes: 7 additions & 1 deletion packages/react/src/Dialog/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ export interface DialogProps extends SxProp {
* instead of the element that had focus immediately before the Dialog opened
*/
returnFocusRef?: React.RefObject<HTMLElement>

/**
* The element to focus when the Dialog opens
*/
initialFocusRef?: React.RefObject<HTMLElement>
}

/**
Expand Down Expand Up @@ -403,6 +408,7 @@ const _Dialog = React.forwardRef<HTMLDivElement, React.PropsWithChildren<DialogP
footerButtons = [],
position = defaultPosition,
returnFocusRef,
initialFocusRef,
sx,
} = props
const dialogLabelId = useId()
Expand All @@ -429,7 +435,7 @@ const _Dialog = React.forwardRef<HTMLDivElement, React.PropsWithChildren<DialogP

useFocusTrap({
containerRef: dialogRef,
initialFocusRef: autoFocusedFooterButtonRef,
initialFocusRef: initialFocusRef ?? autoFocusedFooterButtonRef,
restoreFocusOnCleanUp: returnFocusRef?.current ? false : true,
returnFocusRef,
})
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/__tests__/Dialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {render as HTMLRender, fireEvent} from '@testing-library/react'
import axe from 'axe-core'
import {behavesAsComponent, checkExports} from '../utils/testing'

/* Dialog Version 2 */
/* Dialog Version 1*/

const comp = (
<Dialog isOpen onDismiss={() => null} aria-labelledby="header">
Expand Down

0 comments on commit 71bdfa8

Please sign in to comment.