Skip to content
Magma Design System
Modal<mds-modal>Generated from @maggioli-design-system/magma@2.3.0dist/documentation.json. Encapsulation: shadow.
Correct and idiomatic ways to use the <mds-modal> component, ordered from most common to most specialized. Patterns assume a working knowledge of the shared component rules in agents/conventions.md.
Basic Modal with Inline Content
The simplest form: toggle opened from JavaScript to show the dialog. The built-in close button and backdrop dismiss the modal automatically with interaction="relaxed" (default). React to the mdsModalClose event to sync your state.
<mds-button id="btn-apri">Apri dialogo</mds-button>
<mds-modal id="dialogo">
<div class="p-400">
<mds-text>Sei sicuro di voler continuare?</mds-text>
</div>
</mds-modal>
<script>
const btn = document.getElementById('btn-apri');
const modal = document.getElementById('dialogo');
btn.addEventListener('click', () => { modal.opened = true; });
modal.addEventListener('mdsModalClose', () => { modal.opened = undefined; });
</script>
Fixed Header and Footer via top / bottom Slots
Use the top slot for a sticky header and the bottom slot for a sticky footer (e.g. action buttons). The default slot renders scrollable body content between them.
<mds-modal id="modifica-utente" position="right">
<header slot="top" class="p-400 bg-surface-overlay shadow-ring-weak">
<mds-text typography="h5">Modifica utente</mds-text>
</header>
<div class="p-400 grid gap-400">
<mds-input-field label="Nome">
<mds-input name="nome"></mds-input>
</mds-input-field>
<mds-input-field label="Cognome">
<mds-input name="cognome"></mds-input>
</mds-input-field>
</div>
<footer slot="bottom" class="p-400 flex gap-300 justify-end bg-surface-overlay shadow-ring-weak">
<mds-button variant="dark" tone="outline" id="btn-annulla">Annulla</mds-button>
<mds-button variant="primary" tone="strong" id="btn-salva">Salva</mds-button>
</footer>
</mds-modal>
Edge and Corner Positions
position anchors the window to an edge or corner and drives the slide-in direction. Use right or left for side panels, bottom for mobile drawers.
<!-- Side panel from the right (default in most app shells) -->
<mds-modal id="pannello-laterale" position="right">
<div class="p-400">
<mds-text>Dettagli del documento</mds-text>
</div>
</mds-modal>
<!-- Drawer from the bottom (mobile) -->
<mds-modal id="drawer-mobile" position="bottom">
<div class="p-400">
<mds-text>Azioni disponibili</mds-text>
</div>
</mds-modal>
Strict Interaction Mode
Set interaction="strict" when the user must explicitly confirm or cancel before the dialog closes - for example, a form with unsaved changes. Backdrop clicks and Esc are ignored; only the close button or the close() method can dismiss the modal (a touch swipe still closes it).
<mds-modal id="conferma-elimina" interaction="strict">
<div class="p-400 grid gap-400">
<mds-text typography="h5">Eliminare il documento?</mds-text>
<mds-text>Questa operazione non e' reversibile.</mds-text>
<div class="flex gap-300 justify-end">
<mds-button variant="dark" tone="outline" id="btn-no">Annulla</mds-button>
<mds-button variant="error" tone="strong" id="btn-si">Elimina</mds-button>
</div>
</div>
</mds-modal>
<script>
document.getElementById('btn-no').addEventListener('click', () => {
document.getElementById('conferma-elimina').close();
});
</script>
Programmatic Close via close() Method
Call the async close() method from JavaScript when you need to dismiss the modal from outside its UI - for example, after a successful async operation.
<mds-modal id="salvataggio">
<div class="p-400">
<mds-text>Salvataggio in corso...</mds-text>
</div>
</mds-modal>
<script>
async function salva() {
const modal = document.getElementById('salvataggio');
modal.opened = true;
await salvaRisorsa();
await modal.close();
}
</script>
Listening to Animation Events
mdsModalShow fires when the intro animation completes (the modal is fully visible). Use it to focus the first interactive element. mdsModalHide fires when the outro animation completes; use it to detach the element or reset content.
<mds-modal id="modal-focus" position="right">
<div class="p-400">
<mds-input-field label="Cerca">
<mds-input id="input-ricerca" name="ricerca"></mds-input>
</mds-input-field>
</div>
</mds-modal>
<script>
const modal = document.getElementById('modal-focus');
const input = document.getElementById('input-ricerca');
modal.addEventListener('mdsModalShow', () => {
input.setFocus();
});
modal.addEventListener('mdsModalHide', () => {
// safe point to detach or reset content
modal.opened = undefined;
});
</script>
Custom Animation Styles
animation selects the motion style. 'slide' (default) translates from the entry edge; '3d' adds a perspective tilt; 'custom' delegates entirely to the CSS custom properties --mds-modal-custom-closed-transform and --mds-modal-custom-window-distance.
<!-- 3D perspective tilt animation -->
<mds-modal id="modal-3d" animation="3d" position="center">
<div class="p-400">
<mds-text>Animazione 3D</mds-text>
</div>
</mds-modal>
<!-- Custom animation driven by CSS vars -->
<mds-modal id="modal-custom" animation="custom" position="center">
<div class="p-400">
<mds-text>Animazione personalizzata</mds-text>
</div>
</mds-modal>
Custom Window via window Slot
Slot any element with slot="window" to completely replace the built-in chrome (the window surface and the close button). The slotted element gets no role of its own: the <dialog> the component renders is already the dialog. Use this when a completely bespoke surface is needed - for example, a full-screen banner.
<mds-modal id="modal-banner" animation="custom">
<mds-banner
slot="window"
class="max-w-md w-full mx-400"
tone="box"
deletable
headline="Azione richiesta"
>
<mds-text typography="detail">Conferma la tua identita' per procedere.</mds-text>
<mds-button slot="action" variant="primary" tone="text">Annulla</mds-button>
<mds-button slot="action" variant="primary" tone="strong">Conferma</mds-button>
</mds-banner>
</mds-modal>
Disabling the Backdrop
Add hide-backdrop to render the modal without the dimmed overlay - useful for non-blocking side panels that coexist with interactive page content.
<mds-modal id="pannello-info" position="right" hide-backdrop>
<div class="p-400">
<mds-text>Informazioni contestuali</mds-text>
</div>
</mds-modal>
// Remove the backdrop from JavaScript (it applies from the next opening)
document.getElementById('pannello-info').hideBackdrop = true;
CSS Customization
Style the window surface only through the documented --mds-modal-* CSS custom properties. Set them on the host element.
/* Rounded card-style center modal */
#modal-card {
--mds-modal-window-radius: var(--magma-radius-xl);
--mds-modal-window-distance: calc(var(--spacing) * 600);
--mds-modal-window-overflow: hidden;
--mds-modal-window-background: rgb(var(--magma-surface-overlay));
--mds-modal-window-shadow: var(--shadow-2xl);
--mds-modal-window-max-width: 480px;
}
/* Full-width drawer */
#drawer-bottom {
--mds-modal-window-radius: var(--magma-radius-lg) var(--magma-radius-lg) 0 0;
--mds-modal-window-max-width: 100%;
--mds-modal-window-min-width: 100%;
}