✦ Asteria UI
Components

Modal

Dialog overlay for confirmations, forms, and focused tasks, built on Radix UI.

Installation

npx asteria-ui add modal

Usage

import {
  Modal,
  ModalBody,
  ModalClose,
  ModalContent,
  ModalDescription,
  ModalFooter,
  ModalHeader,
  ModalTitle,
  ModalTrigger,
} from "@/components/ui/modal";

<Modal>
  <ModalTrigger asChild>
    <Button variant="destructive">Delete item</Button>
  </ModalTrigger>
  <ModalContent>
    <ModalHeader>
      <ModalTitle>Delete item?</ModalTitle>
      <ModalClose />
    </ModalHeader>
    <ModalBody>
      <ModalDescription>This action cannot be undone.</ModalDescription>
    </ModalBody>
    <ModalFooter>
      <Button variant="secondary">Cancel</Button>
      <Button variant="destructive">Confirm</Button>
    </ModalFooter>
  </ModalContent>
</Modal>

The close button sits inside ModalHeader as a flex sibling of the title (ModalTitle is flex-1, ModalClose is shrink-0) — that's what the real spec shows, not the more common absolutely-positioned-corner-X pattern. The overlay backdrop is tinted brand-900 at 60% rather than plain black, extending the brand-tinted-shadow principle to the app's other dark surface.

API reference

Modal and ModalTrigger are direct re-exports of Radix Dialog's Root/Trigger. Compose ModalHeader, ModalTitle, ModalClose, ModalBody, ModalDescription, and ModalFooter inside ModalContent — Cancel/Confirm buttons are real <Button> instances you compose in, not baked into Modal itself.

ModalContent

PropTypeDefaultDescription
size"sm" | "md" | "lg""md"Max width — 400 / 560 / 720px.

Accessibility

Accessibility

  • Role. role="dialog" with aria-modal="true" — set explicitly on ModalContent rather than left to Radix's default, since the installed Radix version doesn't set it automatically (verified directly by inspecting the rendered DOM, not assumed).

  • Labelling. aria-labelledby points at ModalTitle, aria-describedby at ModalDescription — wired automatically by Radix.

  • Focus. Trapped within the modal while open.

  • Dismiss. Escape closes it, as does clicking ModalClose or the overlay.