Skip to content

Instantly share code, notes, and snippets.

@ChrisCrossCrash
Last active September 25, 2023 20:38
Show Gist options
  • Save ChrisCrossCrash/f53b4f303d4361c210d8c1d61ce03492 to your computer and use it in GitHub Desktop.
Save ChrisCrossCrash/f53b4f303d4361c210d8c1d61ce03492 to your computer and use it in GitHub Desktop.
A React TypeScript component that uses the `HTMLDialogElement`.
import { useRef, useEffect } from 'react'
type ModalProps = {
className?: string
children: React.ReactNode
/** Whether the modal is currently open or not. */
isOpen: boolean
/** Function to set the modal's visibility state. */
setIsOpen: (isOpen: boolean) => void
/** If true, allows closing the modal by clicking outside of it. Defaults to `false`. */
allowClickOut?: boolean
}
/**
* Modal component using the
* [HTMLDialogElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement).
*
* This component displays its children content inside a modal dialog.
* The modal's visibility is controlled via the `isOpen` prop.
*
* @returns The rendered Modal component.
*/
function Modal(props: ModalProps) {
const modalRef = useRef<HTMLDialogElement>(null)
useEffect(() => {
const modal = modalRef.current
if (modal) {
if (props.isOpen) {
modal.showModal()
} else {
modal.close()
}
}
}, [props.isOpen])
const handleClose = () => {
props.setIsOpen(false)
}
const handleClick = (e: React.MouseEvent<HTMLDialogElement>) => {
// Close the modal if the user clicks outside of it and `allowClickOut` is `true`.
if (!props.allowClickOut) return
const modal = modalRef.current
if (!modal) return
if (
e.clientX < e.currentTarget.offsetLeft ||
e.clientX > e.currentTarget.offsetLeft + e.currentTarget.offsetWidth ||
e.clientY < e.currentTarget.offsetTop ||
e.clientY > e.currentTarget.offsetTop + e.currentTarget.offsetHeight
) {
modal.close()
}
}
return (
<dialog
className={props.className}
ref={modalRef}
onClose={handleClose}
onClick={handleClick}
>
{props.children}
</dialog>
)
}
export default Modal
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment