Salta ai contenuti
Magma Design System
Table<mds-table>Generato da @maggioli-design-system/magma@2.3.0dist/documentation.json. Incapsulamento: shadow.
Questa pagina è generata dai pacchetti Magma, documentati solo in inglese.
Correct and idiomatic ways to use the <mds-table> component, ordered from most common to most specialized. Patterns assume a working knowledge of the shared component rules in agents/conventions.md.
Basic Read-Only Table
The minimal structure: mds-table-header with one mds-table-header-cell per column, mds-table-body with mds-table-row children each containing mds-table-cell elements. All four subparts are required direct children - do not replace them with raw <thead>, <tr>, or <td> elements.
<mds-table>
<mds-table-header>
<mds-table-header-cell label="Nome"></mds-table-header-cell>
<mds-table-header-cell label="Email"></mds-table-header-cell>
<mds-table-header-cell label="Data iscrizione"></mds-table-header-cell>
</mds-table-header>
<mds-table-body>
<mds-table-row>
<mds-table-cell><mds-text typography="detail">Mario Rossi</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">mario.rossi@example.com</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">12 ottobre 1985</mds-text></mds-table-cell>
</mds-table-row>
<mds-table-row>
<mds-table-cell><mds-text typography="detail">Luigi Verdi</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">luigi.verdi@example.com</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">3 marzo 1993</mds-text></mds-table-cell>
</mds-table-row>
</mds-table-body>
</mds-table>
Layout: Fill the Container and Let the Table Scroll
<mds-table> scrolls on its own: its rows sit in an inner wrapper with overflow: auto, so when the columns are wider than the table, the table scrolls horizontally inside its own border, and the row actions (slot="action") stay pinned to the visible right edge. It needs no overflow-x-auto wrapper of yours, but it needs two things from the page: All the width its container offers: w-full on <mds-table>. When that container is a flex or grid item (a main next to a sidebar, a 1fr column), also give the item min-w-0: a flex or grid item never shrinks below its content by default, so without it the item grows to the full width of the table and the whole page scrolls instead of the table.Cells on one line: text-wrap: nowrap on the cells ([&_mds-table-cell]:text-nowrap on the table). Wrapping cells squeeze the columns into tall rows and the table never scrolls. mds-text with typography paragraph, detail or caption sets its own text-wrap: pretty, which wins over what it inherits from the cell, so target it too ([&_mds-text]:text-nowrap). A long free-text column can keep wrapping if it reads better.
<div class="flex">
<aside class="w-6400 shrink-0">...</aside>
<main class="min-w-0 flex-1">
<mds-table class="w-full [&_mds-table-cell]:text-nowrap [&_mds-text]:text-nowrap">
<mds-table-header>
<mds-table-header-cell label="Protocollo"></mds-table-header-cell>
<mds-table-header-cell label="Oggetto"></mds-table-header-cell>
<mds-table-header-cell label="Ufficio"></mds-table-header-cell>
<mds-table-header-cell label="Data"></mds-table-header-cell>
</mds-table-header>
<mds-table-body>
<mds-table-row>
<mds-table-cell><mds-text typography="detail">2026/0412</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">Contratto di fornitura servizi cloud 2026-2028</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">Ufficio acquisti e gare</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">12 marzo 2026</mds-text></mds-table-cell>
</mds-table-row>
</mds-table-body>
</mds-table>
</main>
</div>
To scroll vertically as well, bound the table’s height: in a fixed-height panel, make the panel a flex column and give the table flex-1 min-h-0 (or put h-full or a max-h-* on the table). The header row scrolls with the body, it is not sticky.
<section class="flex h-9600 flex-col">
<mds-table class="min-h-0 flex-1 [&_mds-table-cell]:text-nowrap [&_mds-text]:text-nowrap">
...
</mds-table>
</section>
Without Tailwind, the same rules in CSS:
.content {
min-width: 0;
}
.content mds-table {
width: 100%;
}
.content mds-table-cell,
.content mds-table-cell mds-text {
text-wrap: nowrap;
}
Table with Footer
Add mds-table-footer after mds-table-body to show totals or summaries. Each cell inside the footer is an mds-table-cell - the same component used in body rows.
<mds-table>
<mds-table-header>
<mds-table-header-cell label="Voce"></mds-table-header-cell>
<mds-table-header-cell label="Importo"></mds-table-header-cell>
</mds-table-header>
<mds-table-body>
<mds-table-row>
<mds-table-cell><mds-text typography="detail">Servizio A</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">120,00 EUR</mds-text></mds-table-cell>
</mds-table-row>
<mds-table-row>
<mds-table-cell><mds-text typography="detail">Servizio B</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">80,00 EUR</mds-text></mds-table-cell>
</mds-table-row>
</mds-table-body>
<mds-table-footer>
<mds-table-cell><mds-text typography="action">Totale</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="action">200,00 EUR</mds-text></mds-table-cell>
</mds-table-footer>
</mds-table>
Interactive Rows
Set interactive when rows are clickable or navigable. The prop propagates to every mds-table-row and highlights the hovered row. Do not reach into rows directly to set interactive - set it once on the parent.
<mds-table interactive>
<mds-table-header>
<mds-table-header-cell label="Utente"></mds-table-header-cell>
<mds-table-header-cell label="Ruolo"></mds-table-header-cell>
</mds-table-header>
<mds-table-body>
<mds-table-row>
<mds-table-cell><mds-text typography="detail">Anna Bianchi</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">Amministratore</mds-text></mds-table-cell>
</mds-table-row>
<mds-table-row>
<mds-table-cell><mds-text typography="detail">Carlo Neri</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">Operatore</mds-text></mds-table-cell>
</mds-table-row>
</mds-table-body>
</mds-table>
Row-Level Action Buttons
Slot mds-button elements with slot="action" directly inside mds-table-row (not inside mds-table-cell). The table detects the presence of action buttons and switches to overlay-action mode automatically when content overflows the visible width.
<mds-table interactive>
<mds-table-header>
<mds-table-header-cell label="Documento"></mds-table-header-cell>
<mds-table-header-cell label="Stato"></mds-table-header-cell>
</mds-table-header>
<mds-table-body>
<mds-table-row>
<mds-table-cell><mds-text typography="detail">Contratto 2024.pdf</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">Approvato</mds-text></mds-table-cell>
<mds-button
slot="action"
icon="mi/baseline/download"
title="Scarica documento"
variant="dark"
tone="text"
></mds-button>
<mds-button
slot="action"
icon="mi/baseline/delete"
title="Elimina documento"
variant="error"
tone="text"
></mds-button>
</mds-table-row>
</mds-table-body>
</mds-table>
Row Selection and Selection Event
Set selectable to add a checkbox to each row. Listen for mdsTableSelectionChange to receive the array of selected rows - each entry carries the row index and the optional value set on mds-table-row. Assign value to each row to distinguish selections in the event payload.
<mds-table selectable id="tabella-utenti">
<mds-table-header>
<mds-table-header-cell label="Nome"></mds-table-header-cell>
<mds-table-header-cell label="Reparto"></mds-table-header-cell>
</mds-table-header>
<mds-table-body>
<mds-table-row value="usr-001">
<mds-table-cell><mds-text typography="detail">Giulia Russo</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">Contabilita</mds-text></mds-table-cell>
</mds-table-row>
<mds-table-row value="usr-002">
<mds-table-cell><mds-text typography="detail">Marco Ferrari</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">IT</mds-text></mds-table-cell>
</mds-table-row>
</mds-table-body>
</mds-table>
<script>
document.getElementById('tabella-utenti').addEventListener('mdsTableSelectionChange', (e) => {
console.log('Righe selezionate:', e.detail.rows);
// e.detail.rows => [{ index: 0, value: 'usr-001' }, ...]
});
</script>
Programmatic Select All
Call the selectAll() method to select all rows at once; pass false to deselect. This is a no-op unless selectable is set.
<mds-button id="btn-seleziona-tutti" label="Seleziona tutti" variant="primary" tone="outline"></mds-button>
<mds-button id="btn-deseleziona" label="Deseleziona tutti" variant="dark" tone="text"></mds-button>
<mds-table selectable id="tabella-doc">
<mds-table-header>
<mds-table-header-cell label="Titolo"></mds-table-header-cell>
</mds-table-header>
<mds-table-body>
<mds-table-row value="doc-1">
<mds-table-cell><mds-text typography="detail">Verbale assemblea</mds-text></mds-table-cell>
</mds-table-row>
<mds-table-row value="doc-2">
<mds-table-cell><mds-text typography="detail">Bilancio 2024</mds-text></mds-table-cell>
</mds-table-row>
</mds-table-body>
</mds-table>
<script>
const table = document.getElementById('tabella-doc');
document.getElementById('btn-seleziona-tutti').addEventListener('click', () => table.selectAll());
document.getElementById('btn-deseleziona').addEventListener('click', () => table.selectAll(false));
</script>
Batch Actions Bar
Slot mds-button elements with slot="batch-action" as direct children of mds-table alongside the body. The bar renders only when selectable is set and at least one batch-action button is present; it shows a live count badge of the current selection and appears once a row is checked.
<mds-table selectable>
<mds-table-header>
<mds-table-header-cell label="Pratica"></mds-table-header-cell>
<mds-table-header-cell label="Stato"></mds-table-header-cell>
</mds-table-header>
<mds-table-body>
<mds-table-row value="prat-001">
<mds-table-cell><mds-text typography="detail">Pratica n. 1234</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">In lavorazione</mds-text></mds-table-cell>
</mds-table-row>
<mds-table-row value="prat-002">
<mds-table-cell><mds-text typography="detail">Pratica n. 5678</mds-text></mds-table-cell>
<mds-table-cell><mds-text typography="detail">Chiusa</mds-text></mds-table-cell>
</mds-table-row>
</mds-table-body>
<mds-button
slot="batch-action"
icon="mi/outline/send"
label="Invia selezionati"
variant="dark"
tone="text"
></mds-button>
<mds-button
slot="batch-action"
icon="mi/outline/delete"
label="Elimina selezionati"
variant="error"
tone="text"
></mds-button>
</mds-table>
Sorting by the Back End, with Pages
When the table shows one page of a larger set, set sorting="external": a click on a sortable header emits mdsTableHeaderCellSort with the column (index, and sortKey when the cell has sort-key) and the direction, and moves no row. The application asks the back end for the first page in that order and renders it; the header shows the direction (icon and aria-sort). A direction set by the application, for example restored from the address, is shown the same way.
<mds-table id="practices" sorting="external">
<mds-table-header>
<mds-table-header-cell label="Numero" sortable sort-key="number"></mds-table-header-cell>
<mds-table-header-cell label="Ricevuta il" sortable sort-key="received"></mds-table-header-cell>
<mds-table-header-cell label="Oggetto"></mds-table-header-cell>
</mds-table-header>
<mds-table-body>
<!-- the rows of the current page, rendered by the application -->
</mds-table-body>
</mds-table>
<mds-paginator id="pages" pages="12"></mds-paginator>
const table = document.querySelector('#practices');
const pages = document.querySelector('#pages');
table.addEventListener('mdsTableHeaderCellSort', async (event) => {
const { sortKey, direction } = event.detail;
// direction "none" asks for the order of the back end
await loadPage({ page: 1, sort: direction === 'none' ? undefined : { sortKey, direction } });
pages.currentPage = 1;
});
Styling Customization
Customize the table appearance only through its documented --mds-table-* CSS custom properties. Set them on the host element or a parent selector; use the semantic color roles via rgb(var(--magma-<role>)) so dark mode and themes keep working.
.tabella-contratti mds-table {
--mds-table-background: rgb(var(--magma-surface-raised));
--mds-table-background-alt: rgb(var(--magma-surface-muted));
--mds-table-border-color: rgb(var(--magma-accent-border));
--mds-table-border-width: 1px;
--mds-table-cell-padding: calc(var(--spacing) * 500);
--mds-table-color: rgb(var(--magma-text-default));
}