Skip to content
Magma Design System
Input upload<mds-input-upload>Generated from @maggioli-design-system/magma@2.3.0dist/documentation.json. Encapsulation: shadow.
Common incorrect uses of <mds-input-upload>. 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 Replace the Component with a Raw <input type="file">
<input type="file"> gives you no drag-drop, no per-file validation, no progress bar, and no consistent styling. Use <mds-input-upload> whenever a file upload is needed.
<!-- INCORRECT -->
<input type="file" accept=".pdf" multiple>
<!-- CORRECT -->
<mds-input-upload accept=".pdf" max-files="5"></mds-input-upload>
Do Not Listen to the Native change Event
The internal <input type="file"> lives inside shadow DOM; its native change event may not bubble out or may fire before internal validation completes. Always listen to the documented mdsInputUploadChange event instead.
<!-- INCORRECT -->
<mds-input-upload id="uploader"></mds-input-upload>
<script>
document.querySelector('#uploader').addEventListener('change', (e) => {
console.log(e.target.files); // undefined - input is in shadow DOM
});
</script>
<!-- CORRECT -->
<mds-input-upload id="uploader"></mds-input-upload>
<script>
document.querySelector('#uploader').addEventListener('mdsInputUploadChange', (e) => {
console.log(e.detail); // valid FileList or null
});
</script>
Do Not Append the Files to a FormData Built from the Form
The component already submits its accepted files under name: a FormData built from the form carries them, and appending them again sends every file twice. Give the component a name and let the form carry the files.
<!-- INCORRECT - every file is sent twice -->
<form id="modulo">
<mds-input-upload name="allegati" max-files="3"></mds-input-upload>
</form>
<script type="module">
const form = document.querySelector('#modulo');
const data = new FormData(form);
const files = await form.querySelector('mds-input-upload').getFiles();
Array.from(files).forEach((file) => data.append('allegati', file));
</script>
<!-- CORRECT -->
<form id="modulo">
<mds-input-upload name="allegati" max-files="3"></mds-input-upload>
</form>
<script type="module">
const data = new FormData(document.querySelector('#modulo'));
</script>
Do Not Reach into Shadow DOM for the Hidden Input
The hidden <input type="file"> is an implementation detail inside shadow DOM. Do not query it or read .files directly. Use the getFiles() method or listen to mdsInputUploadChange.
<!-- INCORRECT -->
<mds-input-upload id="upload"></mds-input-upload>
<script>
const input = document.querySelector('#upload').shadowRoot.querySelector('input[type="file"]');
console.log(input.files); // fragile - implementation detail
</script>
<!-- CORRECT -->
<mds-input-upload id="upload"></mds-input-upload>
<script type="module">
const files = await document.querySelector('#upload').getFiles();
console.log(files);
</script>
Do Not Omit sort When You Want the Sort Chooser Visible
The sort tab bar only appears when sort is explicitly set to "date" or "status" and more than one file is present. Omitting sort silently applies the user’s last localStorage preference and hides the chooser. Set sort when you want users to be able to switch the order interactively.
<!-- INCORRECT - sort chooser never appears because sort is omitted -->
<mds-input-upload max-files="10"></mds-input-upload>
<!-- CORRECT - sort chooser appears once more than one file is added -->
<mds-input-upload max-files="10" sort="date"></mds-input-upload>
Do Not Customize Through Undocumented Internal Selectors
The only supported customization surface is the five --mds-input-upload-* CSS custom properties. Do not target internal classes or parts not listed in the API.
/* INCORRECT */
mds-input-upload >>> .drag-area {
background: lightblue;
}
mds-input-upload .main-action {
display: none;
}
/* CORRECT */
mds-input-upload {
--mds-input-upload-drag-area-background-color: rgb(var(--magma-accent-surface-subtle));
--mds-input-upload-drag-area-border: 3px dashed rgb(var(--magma-accent-border));
}
Do Not Use initialValue for Each New File Added by the User
initialValue is for seeding the control once with pre-existing data - for example files already saved to a server. Every assignment re-runs the add pipeline, which emits mdsInputUploadChange again (files already accepted are skipped by name, so nothing is added): reassigning it from that event, as below, loops without end. Let the component manage user-selected files through its own UI.
<!-- INCORRECT - misusing initialValue as a live file binding -->
<mds-input-upload id="uploader"></mds-input-upload>
<script>
document.querySelector('#uploader').addEventListener('mdsInputUploadChange', (e) => {
document.querySelector('#uploader').initialValue = e.detail; // causes re-processing
});
</script>
<!-- CORRECT - just read the value when you need it -->
<mds-input-upload id="uploader"></mds-input-upload>
<script>
document.querySelector('#uploader').addEventListener('mdsInputUploadChange', (e) => {
const files = e.detail; // use directly without re-assigning initialValue
console.log('File correnti:', files ? files.length : 0);
});
</script>