import React, { ElementRef, useRef } from "react";
import { DialogAnchor } from "stream-chat-react";
import { ComponentToDisplayOnDialog } from "./ComponentToDisplayOnDialog";
import { generateUniqueId } from "./generateUniqueId";
const Container = () => {
// DialogAnchor needs a reference element to position the dialog
const buttonRef = useRef<ElementRef<"button">>(null);
// the dialog ID lets you access it via DialogManagerProviderContext
const dialogId = generateUniqueId();
return (
<>
<DialogAnchor
id={dialogId}
placement="top"
referenceElement={buttonRef.current}
trapFocus
>
<ComponentToDisplayOnDialog />
</DialogAnchor>
</>
);
};Dialog Management
Dialog management in the React SDK controls:
- dialog popups like menus (
ReactionSelector,MessageActionsBox,AttachmentSelector,ShareLocationDialog) - modals (if
GlobalModalis used)
Best Practices
- Use
DialogAnchorfor popups andGlobalModalfor full modals. - Keep dialog IDs stable to avoid losing state across renders.
- Use
useDialogIsOpenfor accurate ARIAaria-expandedstates. - Close or remove dialogs on unmount to prevent leaks.
- Avoid stacking multiple dialogs unless the UX requires it.
Setup dialog popup display
There are two parts: the component that requests open/close, and the component that renders the dialog. Start by rendering a component in a dialog.
Rendering a dialog
Wrap the component you want rendered as a floating dialog inside DialogAnchor:
Controlling a dialog's display
The dialog display is controlled via Dialog API. You can access the API via useDialog() hook.
import React, { ElementRef, useRef } from "react";
import { DialogAnchor, useDialog, useDialogIsOpen } from "stream-chat-react";
import { ComponentToDisplayOnDialog } from "./ComponentToDisplayOnDialog";
import { generateUniqueId } from "./generateUniqueId";
const Container = () => {
const buttonRef = useRef<ElementRef<"button">>(null);
const dialogId = generateUniqueId();
// access the dialog controller which provides the dialog API
const dialog = useDialog({ id: dialogId });
// subscribe to dialog open state changes
const dialogIsOpen = useDialogIsOpen(dialogId);
return (
<>
<DialogAnchor
id={dialogId}
placement="top"
referenceElement={buttonRef.current}
trapFocus
>
<ComponentToDisplayOnDialog />
</DialogAnchor>
<button
aria-expanded={dialogIsOpen}
onClick={() => dialog.toggle()}
ref={buttonRef}
>
Toggle
</button>
</>
);
};Dialog API
Control a dialog via the Dialog object from useDialog():
dialog.open()- opens the dialogdialog.close()- closes the dialogdialog.toggle()- toggles open state. AcceptscloseAllto close other open dialogs.dialog.remove()- removes the dialog object reference from the state (primarily for cleanup purposes)
Every Dialog object carries its own id and isOpen flag.
Dialog utility hooks
There are the following utility hooks that can be used to subscribe to state changes or access a given dialog:
useDialogIsOpen(id: string)- allows to observe the open state of a particularDialoginstanceuseDialog({ id }: GetOrCreateDialogParams)- retrieves a dialog object that exposes API to manage ituseOpenedDialogCount()- allows to observe changes in the open dialog count
Custom DialogManagerProvider Context
To render dialogs outside MessageList/VirtualizedMessageList, create a DialogManagerProvider context.
import { DialogManagerProvider } from "stream-chat-react";
const Container = () => {
return (
<DialogManagerProvider id="custom-dialog-manager-id"></DialogManagerProvider>
);
};Now the children of DialogAnchor will be anchored to the parent DialogManagerProvider.
Render Modal with Dialog API
Rendering modals with the Dialog API places them at the top of the Chat tree and avoids UI glitches from CSS positioning (for example, Safari clipping position: fixed under a relative parent).
To start rendering the modal at the top of the chat tree, it is necessary to use GlobalModal for modal rendering:
import { GlobalModal } from "stream-chat-react";
const Component = () => <Channel Modal={GlobalModal}></Channel>;Then render the modal like this:
import { ModalGallery, useComponentContext } from "stream-chat-react";
const Component = () => {
const { Modal } = useComponentContext();
return (
<>
<button>Open Modal</button>
{/* Modal will be renderd via React portal at the top of the tree */}
<Modal
className="modal-gallery-modal"
onClose={closeModal}
open={modalIsOpen}
>
<ModalGallery images={[props]} index={0} />
</Modal>
</>
);
};