|Kit

Modal

Centered overlay dialog on Ark UI's Dialog machine — focus trap, scroll lock, RTL and animated enter/exit, with a flat props API and composable parts.

The Modal is a centered overlay built on Ark UI's Dialog state machine. Ark owns focus-trapping, body scroll-lock, RTL, the Esc / click-outside behaviour and the data-state attribute that drives the enter/exit animations; the kit adds a flat props API plus styled, composable parts.

import { Modal } from '@42/ui-react/modal';

<Modal open={open} onOpenChange={setOpen} title="Welcome">
  <Text>Anything you like in the body.</Text>
</Modal>

To spawn modals imperatively — without useState at every call site — use the overlays manager.

Basic usage

open / onOpenChange make the modal a controlled component. onOpenChange is flattened to (open: boolean) => void.

Code

const [open, setOpen] = useState(false);<Button onClick={() => setOpen(true)}>Open modal</Button><Modal open={open} onOpenChange={setOpen} title="Welcome aboard"><Text>Focus is trapped and the page is scroll-locked while open.</Text></Modal>

Sizes

size maps to the kit's width tokens (xsxl), plus full for a near-fullscreen sheet.

Code

<Modal size="sm" … /><Modal size="md" … />  // default<Modal size="lg" … /><Modal size="xl" … />

Centered

By default the modal anchors near the top of the viewport (so tall content grows downward). Set centered to vertically center it.

Code

<Modal centered title="Centered" … />

Description & close button

title and description render the header; withCloseButton (default true) adds a dogfooded ActionIcon close button.

Code

<Modaltitle="Delete file"description="This action cannot be undone."withCloseButton={false}/>

Composable parts

The high-level <Modal> covers the common case. For full control over structure, compose the parts directly — they carry the same styling and Ark wiring:

<Modal.Root open={open} onOpenChange={({ open }) => setOpen(open)}>
  <Modal.Trigger asChild>
    <Button>Open</Button>
  </Modal.Trigger>
  <Modal.Backdrop />
  <Modal.Positioner centered>
    <Modal.Content size="md">
      <Modal.Header>
        <Modal.Title>Custom layout</Modal.Title>
        <Modal.CloseTrigger />
      </Modal.Header>
      <Modal.Body>…</Modal.Body>
      <Modal.Footer>
        <Button variant="default">Cancel</Button>
        <Button>Save</Button>
      </Modal.Footer>
    </Modal.Content>
  </Modal.Positioner>
</Modal.Root>

API

Prop

Type

All other props (modal, trapFocus, preventScroll, id, lazyMount, …) forward to Ark's Dialog.Root.

Accessibility

  • Ark traps focus inside the content while open and restores it to the trigger on close.
  • The body is scroll-locked (preventScroll) and content below is hidden from assistive tech (modal).
  • title wires aria-labelledby and description wires aria-describedby automatically. When you omit a title, pass an aria-label.
  • Animations collapse to a 1ms opacity tween under prefers-reduced-motion.

On this page