Skip to content
Magma Design System
Dropdown<mds-dropdown>Generated from @maggioli-design-system/magma@2.3.0dist/documentation.json. Encapsulation: shadow.
Correct and idiomatic ways to use the <mds-dropdown> component, ordered from most common to most specialized. Patterns assume a working knowledge of the shared component rules in agents/conventions.md.
Basic Dropdown Menu
The minimal required setup: a trigger element with a unique id and a <mds-dropdown> with target pointing at it. The dropdown binds to the caller on click by default and dismisses on outside-click or Escape.
<mds-button id="menu-utente" label="Profilo" icon="mi/baseline/account-circle" variant="primary" tone="weak"></mds-button>
<mds-dropdown target="#menu-utente">
<mds-button icon="mi/baseline/settings" variant="dark" tone="text" label="Impostazioni account"></mds-button>
<mds-button icon="mi/baseline/logout" variant="error" tone="text" label="Esci"></mds-button>
</mds-dropdown>
Panel That Is Not a Menu
The dropdown is a menu by default, a list of actions being what it holds most of the time. A panel that holds anything else - a calendar, a form, a paragraph with a link - declares its own role, which the component never overwrites: its contents are then left alone instead of being named entries of a menu.
<mds-button id="info-policy" label="Come usiamo i tuoi dati" variant="primary" tone="weak"></mds-button>
<mds-dropdown target="#info-policy" role="group">
<mds-text typography="tip">I dati restano sui server di Maggioli.</mds-text>
<mds-button href="/policy" label="Leggi la policy" variant="dark" tone="text" size="sm"></mds-button>
</mds-dropdown>
Dropdown with Arrow Pointer
The arrow pointer is shown by default to visually connect the panel to its caller; add hide-arrow to remove it. Adjust arrow-padding when the panel is narrow and the arrow would clip the rounded corners.
<mds-button id="aiuto-contestuale" label="Aiuto" icon="mi/baseline/help-outline" variant="primary" tone="outline"></mds-button>
<mds-dropdown target="#aiuto-contestuale" arrow-padding="16">
<mds-text typography="h6">Come funziona?</mds-text>
<mds-text typography="detail">Seleziona un campo per vedere la guida contestuale.</mds-text>
</mds-dropdown>
Dropdown with Backdrop
Use backdrop to dim the rest of the page while the panel is open. This is appropriate for panels with a higher modal weight, such as user-account menus or multi-step pickers.
<mds-button id="selezione-filtri" label="Filtra risultati" icon="mi/baseline/filter-list" variant="primary"></mds-button>
<mds-dropdown target="#selezione-filtri" backdrop>
<mds-text typography="h6">Filtra per categoria</mds-text>
<mds-filter>
<mds-filter-item label="Documenti"></mds-filter-item>
<mds-filter-item label="Immagini"></mds-filter-item>
<mds-filter-item label="Video"></mds-filter-item>
</mds-filter>
</mds-dropdown>
Mouseover Interaction
Set interaction="mouseover" for navigation mega-menus or info tooltips that should open on hover. The component adds a configurable delay (default 0.5 s, controlled by --mds-dropdown-mouseover-delay) before opening and closing.
<mds-button id="info-progetto" label="Dettagli progetto" variant="dark" tone="text"></mds-button>
<mds-dropdown target="#info-progetto" interaction="mouseover">
<mds-entity icon="mi/baseline/folder">
<mds-text>Progetto Alfa - In corso</mds-text>
</mds-entity>
</mds-dropdown>
Programmatic Control via visible
Set interaction="none" to disable automatic wiring and drive visibility yourself. This is useful when the trigger logic lives in app code - for example, opening on a keyboard shortcut or a programmatic state change.
<mds-button id="apri-manuale" label="Apri pannello" variant="primary"></mds-button>
<mds-dropdown id="pannello-opzioni" target="#apri-manuale" interaction="none">
<mds-text typography="detail">Pannello gestito dal codice applicativo.</mds-text>
</mds-dropdown>
<script>
const dropdown = document.querySelector('#pannello-opzioni');
document.querySelector('#apri-manuale').addEventListener('click', () => {
dropdown.visible = !dropdown.visible;
});
</script>
Placement and Auto-Placement
Use placement to anchor the panel to a specific side of the caller. Auto-placement is on by default, letting the component choose the best available side based on viewport space; add disable-auto-placement to pin the panel strictly to placement.
<!-- Pinned right-start placement (auto-placement disabled) -->
<mds-button id="azioni-riga" label="Azioni" icon="mi/baseline/more-vert" variant="dark" tone="text"></mds-button>
<mds-dropdown target="#azioni-riga" placement="right-start" disable-auto-placement>
<mds-button icon="mi/baseline/edit" variant="dark" tone="text" label="Modifica"></mds-button>
<mds-button icon="mi/baseline/delete" variant="error" tone="text" label="Elimina"></mds-button>
</mds-dropdown>
<!-- Auto-placement (default) for constrained viewports -->
<mds-button id="opzioni-voce" label="Opzioni" variant="primary" tone="weak"></mds-button>
<mds-dropdown target="#opzioni-voce">
<mds-button label="Duplica" icon="mi/baseline/content-copy" variant="dark" tone="text"></mds-button>
</mds-dropdown>
Flip and Shift for Viewport Safety
Enable flip to let the panel jump to the opposite side when there is not enough space in the preferred direction; it acts only with disable-auto-placement, since auto-placement already picks the side and ignores both placement and flip. Shifting the panel to keep it inside the viewport is on by default; tune the safe margin with shift-padding (or set disable-shift to opt out).
<mds-button id="btn-edge" label="Vicino al bordo" variant="primary"></mds-button>
<mds-dropdown target="#btn-edge" placement="top" disable-auto-placement flip shift-padding="16">
<mds-text typography="detail">Questo pannello si sposta automaticamente se manca spazio.</mds-text>
</mds-dropdown>
Listening to Visibility Events
Listen for mdsDropdownVisible, mdsDropdownHide, or mdsDropdownChange to react to open/close transitions. Each event detail contains caller (the resolved trigger element) and visible (the new state).
<mds-button id="btn-notifica" label="Notifiche" icon="mi/baseline/notifications" variant="primary"></mds-button>
<mds-dropdown id="pannello-notifiche" target="#btn-notifica">
<mds-text typography="detail">Nessuna nuova notifica.</mds-text>
</mds-dropdown>
<script>
document.querySelector('#pannello-notifiche').addEventListener('mdsDropdownVisible', (e) => {
console.log('Aperto. Trigger:', e.detail.caller);
});
document.querySelector('#pannello-notifiche').addEventListener('mdsDropdownHide', () => {
console.log('Chiuso.');
});
</script>
Strategy fixed Inside Scrolling or Stacked Containers
Use strategy="fixed" when the dropdown is placed inside a scroll container, a sticky header, or a modal. With strategy="absolute" (the default) the panel may be clipped by overflow: hidden ancestors.
<!-- Inside a modal or a sticky nav - use fixed positioning -->
<mds-button id="menu-header" label="Menu" variant="primary" tone="weak"></mds-button>
<mds-dropdown target="#menu-header" strategy="fixed">
<mds-button label="Pagina principale" icon="mi/baseline/home" variant="dark" tone="text"></mds-button>
<mds-button label="Impostazioni" icon="mi/baseline/settings" variant="dark" tone="text"></mds-button>
</mds-dropdown>
DOM Placement at the Document Root
Place <mds-dropdown> as a direct child of <body> (or as close as possible to the root) when the caller lives deep inside a stacking context. Nesting the dropdown inside the same transformed or overflow: hidden ancestor as the caller can break positioning and backdrop rendering.
<body>
<!-- Trigger lives inside a complex layout -->
<div class="app-layout">
<nav>
<mds-button id="btn-profilo" label="Profilo" variant="primary"></mds-button>
</nav>
</div>
<!-- Dropdown is a sibling of the layout root, not nested inside it -->
<mds-dropdown target="#btn-profilo" strategy="fixed" backdrop>
<mds-text typography="h6">Mario Rossi</mds-text>
<mds-button label="Esci" icon="mi/baseline/logout" variant="error" tone="text"></mds-button>
</mds-dropdown>
</body>
Styling Customization
Customize the dropdown only through its documented --mds-dropdown-* CSS custom properties. Use the semantic color roles via rgb(var(--magma-<role>)) to preserve dark-mode, named-theme and high-contrast behavior.
.my-context mds-dropdown {
--mds-dropdown-background: rgb(var(--magma-surface-overlay));
--mds-dropdown-drop-shadow-color-rgb: var(--magma-accent-emphasis);
--mds-dropdown-duration: 0.3s;
--mds-dropdown-mouseover-delay: 0.2s;
--mds-dropdown-z-index: 5000;
}