Modal
A component that displays content in a window that requires user interaction.@coinbase/cds-web@8.38.5
import { Modal } from '@coinbase/cds-web/overlays/modal/Modal'
Peer dependencies
- framer-motion: ^10.18.0
Related components
Basic example
Loading...
Live Codefunction Example() { const [visible, setVisible] = useState(false); return ( <> <Button onClick={() => setVisible(true)}>Open Modal</Button> <Modal onRequestClose={() => setVisible(false)} visible={visible}> <ModalHeader backAccessibilityLabel="Back" closeAccessibilityLabel="Close" onBackButtonClick={() => setVisible(false)} testID="Basic Modal Test ID" title="Basic Modal" /> <ModalBody tabIndex={0} testID="modal-body"> Body contents go here </ModalBody> <ModalFooter primaryAction={<Button onClick={() => setVisible(false)}>Save</Button>} secondaryAction={ <Button onClick={() => setVisible(false)} variant="secondary"> Cancel </Button> } /> </Modal> </> ); }
Portal Modal
This approach is deprecated
Use the visible and onRequestClose props as outlined above
Loading...
Live Codefunction Example() { const { openModal, closeModal } = useModal(); const handlePress = useCallback( () => openModal( <Modal visible onRequestClose={closeModal}> <ModalHeader closeAccessibilityLabel="Close" title="Default Modal" /> <ModalBody>Body contents go here</ModalBody> <ModalFooter primaryAction={<Button onClick={closeModal}>Save</Button>} secondaryAction={ <Button onClick={closeModal} variant="secondary"> Cancel </Button> } /> </Modal>, ), [openModal, closeModal], ); return <Button onClick={handlePress}>Open Modal</Button>; }
Chained Modals
Accessibility tip
For chained modals, set restoreFocusOnUnmount={false} on each one and return focus to the opener when exiting the chain (e.g., triggerRef.current?.focus()) to keep tab order predictable.
Loading...
Live Codefunction ChainedModalsExample() { const triggerRef = useRef(null); const [isFirstModalOpen, setIsFirstModalOpen] = useState(false); const [isSecondModalOpen, setIsSecondModalOpen] = useState(false); const closeFirstModal = () => { setIsFirstModalOpen(false); triggerRef.current?.focus(); }; const openSecondModal = () => { setIsFirstModalOpen(false); setIsSecondModalOpen(true); }; const closeSecondModal = () => { setIsSecondModalOpen(false); triggerRef.current?.focus(); }; const goBackToFirstModal = () => { setIsSecondModalOpen(false); setIsFirstModalOpen(true); }; return ( <> <Button ref={triggerRef} onClick={() => setIsFirstModalOpen(true)}> Open Modal </Button> <Modal onRequestClose={closeFirstModal} restoreFocusOnUnmount={false} visible={isFirstModalOpen} > <ModalHeader closeAccessibilityLabel="Close" onBackButtonClick={closeFirstModal} title="First Modal" /> <ModalBody tabIndex={0} testID="first-modal-body"> <Text>First modal content</Text> </ModalBody> <ModalFooter primaryAction={<Button onClick={openSecondModal}>Next</Button>} secondaryAction={ <Button onClick={closeFirstModal} variant="secondary"> Cancel </Button> } /> </Modal> <Modal onRequestClose={closeSecondModal} restoreFocusOnUnmount={false} visible={isSecondModalOpen} > <ModalHeader closeAccessibilityLabel="Close" onBackButtonClick={goBackToFirstModal} title="Second Modal" /> <ModalBody tabIndex={0} testID="second-modal-body"> <Text>Second modal content</Text> </ModalBody> <ModalFooter primaryAction={<Button onClick={closeSecondModal}>Close</Button>} secondaryAction={ <Button onClick={closeSecondModal} variant="secondary"> Cancel </Button> } /> </Modal> </> ); }