Skip to content
Magma Design System
Tree item<mds-tree-item>Generated from @maggioli-design-system/magma@2.3.0dist/documentation.json. Encapsulation: shadow.
Common incorrect uses of <mds-tree-item>. Each entry pairs the wrong form with the right one and a one-line reason. System-wide rules (boolean-as-string, shadow piercing, Tailwind color utilities, raw native event listening) live in agents/anti-patterns.md - they apply here too but are not repeated.
Do Not Use the Default Slot for Arbitrary Content
The default slot accepts only <mds-tree-item> children. Slotting arbitrary HTML (text, icons, buttons) into the default slot does not produce a label or a nested item - use the label prop for text and the action slot for action controls.
<!-- INCORRECT -->
<mds-tree-item>
<span>Documenti</span>
<mds-button icon="mi/baseline/add" title="Aggiungi documento"></mds-button>
</mds-tree-item>
<!-- CORRECT -->
<mds-tree-item label="Documenti">
<mds-button
slot="action"
icon="mi/baseline/add"
title="Aggiungi documento"
variant="primary"
tone="text"
></mds-button>
</mds-tree-item>
Do Not Use the action Slot for Child Nodes
The action slot is for contextual controls (buttons, icons). Putting a <mds-tree-item> in the action slot removes it from the expand/collapse tree hierarchy and breaks branch rendering.
<!-- INCORRECT -->
<mds-tree-item label="Cartella">
<mds-tree-item slot="action" label="Figlio"></mds-tree-item>
</mds-tree-item>
<!-- CORRECT -->
<mds-tree-item label="Cartella">
<mds-tree-item label="Figlio"></mds-tree-item>
</mds-tree-item>
Do Not Set expanded="false" to Close a Node
Stencil reads the exact string "false" as false, so the node renders closed, but the attribute stays on the element: the chevron, styled on the attribute, points open, and presence checks (hasAttribute('expanded')) read the node as open. Remove the attribute (or set the property to undefined) to close.
<!-- INCORRECT -->
<mds-tree-item label="Archivio" expanded="false"></mds-tree-item>
<!-- CORRECT -->
<mds-tree-item label="Archivio"></mds-tree-item>
Do Not Use mds-tree-item Outside a Tree Context
<mds-tree-item> is a compound child - it must be a direct slot child of <mds-tree> or of another <mds-tree-item>. Using it in isolation removes the branch context, depth assignments, and coordinated expand/collapse behavior.
<!-- INCORRECT -->
<div class="my-list">
<mds-tree-item label="Voce 1"></mds-tree-item>
<mds-tree-item label="Voce 2"></mds-tree-item>
</div>
<!-- CORRECT -->
<mds-tree>
<mds-tree-item label="Voce 1"></mds-tree-item>
<mds-tree-item label="Voce 2"></mds-tree-item>
</mds-tree>
Do Not Set depth Manually
depth is an internal prop set by the parent <mds-tree>: it marks first-level items with 0, which removes their branch connector lines (indentation comes from the nesting, not from depth). A hand-set value is useless at best, and a 0 on a nested item strips the connectors from the wrong level.
<!-- INCORRECT -->
<mds-tree>
<mds-tree-item label="Primo livello" depth="0">
<mds-tree-item label="Secondo livello" depth="1"></mds-tree-item>
</mds-tree-item>
</mds-tree>
<!-- CORRECT -->
<mds-tree>
<mds-tree-item label="Primo livello">
<mds-tree-item label="Secondo livello"></mds-tree-item>
</mds-tree-item>
</mds-tree>
Do Not Pierce the Shadow DOM to Style Internals
The only supported customization surface is --mds-tree-item-* CSS custom properties and the two documented shadow parts (actions-container, actions-list). Targeting internal classes via >>>, /deep/, or undocumented ::part() names couples your code to implementation details that can change on any minor release.
/* INCORRECT */
mds-tree-item >>> .label-action {
font-weight: bold;
}
mds-tree-item::part(toggle-icon) {
color: red;
}
/* CORRECT */
mds-tree-item {
--mds-tree-item-label-hover-background: rgb(var(--magma-wash-base));
--mds-tree-item-toggle-icon-chevron-default-color: rgb(var(--magma-accent-on-emphasis));
}
mds-tree-item::part(actions-list) {
gap: calc(var(--spacing) * 200);
}
Do Not Call expand() Instead of Handling Async Correctly
expand() is the public method for resolving an async load - it opens the node and clears the spinner. Calling it immediately on the mdsTreeItemExpand event (before data is fetched) opens an empty branch and discards the loading affordance. Always await the data before calling expand().
<!-- INCORRECT -->
<script>
node.addEventListener('mdsTreeItemExpand', (event) => {
event.detail.element.expand(); // opens immediately, before data arrives
fetchChildren().then((data) => { /* too late */ });
});
</script>
<!-- CORRECT -->
<script>
node.addEventListener('mdsTreeItemExpand', async (event) => {
const el = event.detail.element;
if (!el.async) return;
const data = await fetchChildren();
data.forEach((name) => {
const child = document.createElement('mds-tree-item');
child.label = name;
el.appendChild(child);
});
await el.expand();
el.async = undefined;
});
</script>