(
function DialogHeader({ children, className, ...rest }, ref) {
- const ctx = useContext(DialogContext)
+ const ctx = useDialogContext()
return (
(
tone="accent"
icon
round
- onClick={() => ctx?.close()}
+ onClick={() => ctx.close()}
aria-label="Close"
>
@@ -168,12 +245,11 @@ DialogHeader.displayName = 'Dialog.Header'
const DialogTitle = forwardRef(
function DialogTitle({ id, className, children, ...rest }, ref) {
- const ctx = useContext(DialogContext)
+ const ctx = useDialogContext()
const generatedId = useId()
const resolvedId = id ?? generatedId
useEffect(() => {
- if (!ctx) return
return ctx.registerTitle(resolvedId)
}, [ctx, resolvedId])
@@ -226,6 +302,9 @@ type CompoundDialog = typeof DialogRoot & {
Title: typeof DialogTitle
Content: typeof DialogContent
Actions: typeof DialogActions
+ Trigger: typeof DialogTrigger
+ Popup: typeof DialogPopup
+ Close: typeof DialogClose
}
export const Dialog = DialogRoot as CompoundDialog
@@ -233,3 +312,14 @@ Dialog.Header = DialogHeader
Dialog.Title = DialogTitle
Dialog.Content = DialogContent
Dialog.Actions = DialogActions
+Dialog.Trigger = DialogTrigger
+Dialog.Popup = DialogPopup
+Dialog.Close = DialogClose
+
+const useDialogContext = () => {
+ const ctx = useContext(DialogContext)
+ if (!ctx) {
+ throw new Error('Dialog compound components must be wrapped in ')
+ }
+ return ctx
+}
diff --git a/packages/eds-core-react/src/components/next/Dialog/Dialog.types.ts b/packages/eds-core-react/src/components/next/Dialog/Dialog.types.ts
index f32f5c1466..38904063b8 100644
--- a/packages/eds-core-react/src/components/next/Dialog/Dialog.types.ts
+++ b/packages/eds-core-react/src/components/next/Dialog/Dialog.types.ts
@@ -5,13 +5,17 @@ export type DialogProps = {
* Controlled open state. When true, the dialog is shown via the native
* `HTMLDialogElement.showModal()` (modal mode: focus trap + inert background).
*/
- open: boolean
+ open?: boolean
/**
* Called when the dialog requests to close — via Escape key, backdrop click,
* or the header close button. Update your `open` state in response; the
* component is fully controlled.
*/
- onOpenChange: (open: boolean) => void
+ onOpenChange?: (open: boolean) => void
+ children: ReactNode
+}
+
+export type DialogPopupProps = {
/**
* Whether to render a visible backdrop (scrim) behind the dialog.
* Defaults to true. Set to false for transparent backdrops.