Modal
An accessible dialog overlay rendered via Teleport / Portal to
<body>. Traps focus, closes on Escape, and blocks background scroll.
Basic
import { useState } from "react";
import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from "@usevyre/react";
function Example() {
const [open, setOpen] = useState(false);
return (
<>
<Button variant="accent" onClick={() => setOpen(true)}>Open modal</Button>
<Modal open={open} onClose={() => setOpen(false)}>
<ModalHeader>
<h2>Confirm deletion</h2>
</ModalHeader>
<ModalBody>
<p>This action cannot be undone.</p>
</ModalBody>
<ModalFooter>
<Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
<Button variant="danger">Delete</Button>
</ModalFooter>
</Modal>
</>
);
} <script setup>
import { ref } from "vue";
import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from "@usevyre/vue";
const open = ref(false);
</script>
<template>
<Button variant="accent" @click="open = true">Open modal</Button>
<Modal :open="open" @close="open = false">
<ModalHeader>
<h2>Confirm deletion</h2>
</ModalHeader>
<ModalBody>
<p>This action cannot be undone.</p>
</ModalBody>
<ModalFooter>
<Button variant="ghost" @click="open = false">Cancel</Button>
<Button variant="danger">Delete</Button>
</ModalFooter>
</Modal>
</template> Sizes
Use the size prop to control the modal panel width.
"full" fills the entire viewport.
<Modal open={open} onClose={close} size="sm">...</Modal>
<Modal open={open} onClose={close} size="md">...</Modal> {/* default */}
<Modal open={open} onClose={close} size="lg">...</Modal>
<Modal open={open} onClose={close} size="full">...</Modal> <Modal :open="open" @close="open = false" size="sm">...</Modal>
<Modal :open="open" @close="open = false" size="md">...</Modal>
<Modal :open="open" @close="open = false" size="lg">...</Modal>
<Modal :open="open" @close="open = false" size="full">...</Modal> Accessibility
Modal renders role="dialog" with aria-modal="true".
Focus is trapped inside and returns to the trigger element on close.
Keyboard: Escape closes, Tab cycles through focusable elements.
Props
Props
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controls visibility. Required. |
onClose / @close | () => void | — | Called when the user dismisses the modal (Escape key or backdrop click). |
size | "sm" | "md" | "lg" | "full" | "md" | Modal width. |
closeOnBackdrop | boolean | true | Close when clicking the backdrop. |
closeOnEsc | boolean | true | Close when pressing Escape. |
class / className | string | — | Additional CSS class on the modal panel. |
Valid props
| Prop | Values | Default |
|---|---|---|
size | "sm"|"md"|"lg"|"full" | md |
open | true|false | false |
Common AI mistakes
- size="xl"→ Use size="lg" or size="full"
Quick examples
Confirmation modal
<Modal open={isOpen} onClose={() => setIsOpen(false)} title="Confirm Delete" size="sm">
<ModalBody>Are you sure you want to delete this item?</ModalBody>
<ModalFooter>
<Button variant="ghost" onClick={() => setIsOpen(false)}>Cancel</Button>
<Button variant="danger" onClick={handleDelete}>Delete</Button>
</ModalFooter>
</Modal>