Modal

Accessible dialog with focus trap, Escape to close, scroll lock, and optional footer.

Basic

import { useState } from 'react'
import { Modal, Button } from '@canarist/ui'

function Example() {
  const [open, setOpen] = useState(false)
  return (
    <>
      <Button onClick={() => setOpen(true)}>Open Modal</Button>
      <Modal
        open={open}
        onClose={() => setOpen(false)}
        aria-labelledby="modal-title"
      >
        <h2 id="modal-title">Modal Title</h2>
        <p>Modal content goes here.</p>
      </Modal>
    </>
  )
}

<Modal
  open={open}
  onClose={() => setOpen(false)}
  aria-labelledby="modal-title"
  footer={
    <div className="flex justify-end gap-2">
      <Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
      <Button onClick={() => setOpen(false)}>Confirm</Button>
    </div>
  }
>
  <h2 id="modal-title">Confirm Action</h2>
  <p>Are you sure you want to continue?</p>
</Modal>

Reference

PropTypeDefaultDescription
openbooleanWhether the modal is visible.
onClose() => voidCalled when clicking the backdrop, close button, or pressing Escape.
childrenReactNodeScrollable body content.
footerReactNodeSticky footer area, typically action buttons.
aria-labelledbystringID of the element labeling the dialog (required for accessibility).
aria-describedbystringID of the element describing the dialog.
classNamestringAdditional CSS classes on the dialog panel.