Start typing to search components and docs…
select navigate ESC close

Modal

Native modal window based on <dialog> tag with ::backdrop CSS pseudo-element. Features built-in X close button, action buttons, and flexible configuration.

Documentation:

Basic Modal with Title and X Button

Modal.astro is Astro-only (uses <script>). Import via subpath, not the barrel.

<button onclick="document.getElementById('dialog1').showModal()">Open modal</button>
<dialog id="dialog1">
<div class="modal-header">
  <h2>Modal Title</h2>
  <button class="modal-close-x" onclick="this.closest('dialog').close()" aria-label="Close"></button>
</div>
<div class="modal-content">
  <p>This modal has a title and built-in X close button.</p>
  <p>You can also close by clicking the backdrop or pressing Escape.</p>
</div>
</dialog>
<Modal id="dialog2" open="Delete Item" title="Confirm Delete" showActions cancelText="Cancel" confirmText="Delete">
<p>Are you sure you want to delete this item? This action cannot be undone.</p>
</Modal>
---
import Modal from 'spoko-design-system/components/Modal.astro';
import Button from 'spoko-design-system/components/Button.vue';
---
<Modal id="dialog3" open="Save Changes" title="Save Document" showActions>
<p>Would you like to save your changes before closing?</p>

<div slot="actions" class="flex gap-3 justify-end">
  <form method="dialog" class="contents">
    <Button>Don't Save</Button>
  </form>
  <form method="dialog" class="contents">
    <Button primary>Save</Button>
  </form>
</div>
</Modal>
<Modal id="dialog4" open="Wide Modal" title="Large Content" maxWidth="900px">
<p>This modal is wider than the default. Useful for forms or detailed content.</p>
<div class="grid grid-cols-2 gap-4 mt-4">
  <div class="p-4 bg-gray-100 rounded">Column 1</div>
  <div class="p-4 bg-gray-100 rounded">Column 2</div>
</div>
</Modal>
<Modal id="dialog5" open="Open modal" title="Custom Close" showXButton={false}>
<p>This modal doesn't have the X button.</p>
<p>You need to provide your own close button.</p>
<Button primary slot="close" class="mt-4">Close Modal</Button>
</Modal>
---
import Modal from 'spoko-design-system/components/Modal.astro';
import Button from 'spoko-design-system/components/Button.vue';
import { Icon } from 'astro-icon/components';
---
<Modal id="dialog6" open="Open modal" title="Icon Close" showXButton={false}>
<p>Some extra content you would like here</p>
<Button primary slot="close" class="mt-4"><Icon name="octicon:x-24" /></Button>
</Modal>

Handling Confirm Events

You can listen for the confirm event when using action buttons:

document.getElementById('dialog2').addEventListener('confirm', (e) => {
     console.log('Confirmed!', e.detail);
     // Perform your action here
     document.getElementById('dialog2').close();
});

Props

PropTypeDefaultDescription
id*stringUnique identifier for the modal
openstring'Open modal'Text for the trigger button
titlestringundefinedModal title (shown in header)
maxWidthstring'600px'Maximum width of the modal
showXButtonbooleantrueShow X close button in top-right
showTriggerbooleantrueShow the trigger button
showActionsbooleanfalseShow action buttons footer
cancelTextstring'Cancel'Text for cancel button
confirmTextstring'Confirm'Text for confirm button
confirmPrimarybooleantrueMake confirm button primary style

Slots

Slot Description
default Main modal content (alias for main slot)
main Main modal content
header Custom header content (replaces title)
actions Custom action buttons (when showActions is true)
close Custom close button (when showActions is false)

Features

  • ✅ Built-in X close button in top-right corner
  • ✅ Click backdrop to close
  • ✅ Press Escape to close
  • ✅ Built-in action buttons (Cancel/Confirm)
  • ✅ Customizable width
  • ✅ TypeScript support
  • ✅ Fully accessible with ARIA labels