diff --git a/src/components/action-menu/action-menu.jsx b/src/components/action-menu/action-menu.jsx
index 36cf5d4449f7ddd1815cb5388d3784915a709a3e..f9e50f3ff667e02ff78cc5d345e761993e9b8709 100644
--- a/src/components/action-menu/action-menu.jsx
+++ b/src/components/action-menu/action-menu.jsx
@@ -142,7 +142,7 @@ class ActionMenu extends React.Component {
                 <div className={styles.moreButtonsOuter}>
                     <div className={styles.moreButtons}>
                         {(moreButtons || []).map(({img, title, onClick: handleClick,
-                            fileAccept, fileChange, fileInput}, keyId) => {
+                            fileAccept, fileChange, fileInput, fileMultiple}, keyId) => {
                             const isComingSoon = !handleClick;
                             const hasFileInput = fileInput;
                             const tooltipId = `${this.mainTooltipId}-${title}`;
@@ -166,6 +166,7 @@ class ActionMenu extends React.Component {
                                             <input
                                                 accept={fileAccept}
                                                 className={styles.fileInput}
+                                                multiple={fileMultiple}
                                                 ref={fileInput}
                                                 type="file"
                                                 onChange={fileChange}
@@ -198,7 +199,8 @@ ActionMenu.propTypes = {
         onClick: PropTypes.func, // Optional, "coming soon" if no callback provided
         fileAccept: PropTypes.string, // Optional, only for file upload
         fileChange: PropTypes.func, // Optional, only for file upload
-        fileInput: PropTypes.func // Optional, only for file upload
+        fileInput: PropTypes.func, // Optional, only for file upload
+        fileMultiple: PropTypes.bool // Optional, only for file upload
     })),
     onClick: PropTypes.func.isRequired,
     title: PropTypes.node.isRequired,
diff --git a/src/components/sprite-selector/sprite-selector.jsx b/src/components/sprite-selector/sprite-selector.jsx
index 115eaee955f25d6ccba82b86c7f8206cc0ee3719..d834f43b03bd44a23ce4fe6326543670439dbe27 100644
--- a/src/components/sprite-selector/sprite-selector.jsx
+++ b/src/components/sprite-selector/sprite-selector.jsx
@@ -122,7 +122,8 @@ const SpriteSelectorComponent = function (props) {
                         onClick: onFileUploadClick,
                         fileAccept: '.svg, .png, .jpg, .jpeg, .sprite2, .sprite3',
                         fileChange: onSpriteUpload,
-                        fileInput: spriteFileInput
+                        fileInput: spriteFileInput,
+                        fileMultiple: true
                     }, {
                         title: intl.formatMessage(messages.addSpriteFromSurprise),
                         img: surpriseIcon,
diff --git a/src/components/stage-selector/stage-selector.jsx b/src/components/stage-selector/stage-selector.jsx
index 64a1948a82670324221c5743f0657e9215d89677..db89a67c5a961a5419d7bf5cb850bd75ae504813 100644
--- a/src/components/stage-selector/stage-selector.jsx
+++ b/src/components/stage-selector/stage-selector.jsx
@@ -104,7 +104,8 @@ const StageSelector = props => {
                         onClick: onBackdropFileUploadClick,
                         fileAccept: '.svg, .png, .jpg, .jpeg', // Bitmap coming soon
                         fileChange: onBackdropFileUpload,
-                        fileInput: fileInputRef
+                        fileInput: fileInputRef,
+                        fileMultiple: true
                     }, {
                         title: intl.formatMessage(messages.addBackdropFromSurprise),
                         img: surpriseIcon,
diff --git a/src/containers/costume-tab.jsx b/src/containers/costume-tab.jsx
index 39e0419acdd720dec654f37bf9244dfe2014e573..3817c4f3c9fda0b4111194eaa95298bd5abe4285 100644
--- a/src/containers/costume-tab.jsx
+++ b/src/containers/costume-tab.jsx
@@ -293,7 +293,8 @@ class CostumeTab extends React.Component {
                         onClick: this.handleFileUploadClick,
                         fileAccept: '.svg, .png, .jpg, .jpeg',
                         fileChange: this.handleCostumeUpload,
-                        fileInput: this.setFileInput
+                        fileInput: this.setFileInput,
+                        fileMultiple: true
                     },
                     {
                         title: intl.formatMessage(messages.addSurpriseCostumeMsg),
diff --git a/src/containers/sound-tab.jsx b/src/containers/sound-tab.jsx
index 3880de2e5349d3df811651a96846cb5c9b06e1a8..9db3289d96d9eeb61b30a6d5fbe60244b5ec61a1 100644
--- a/src/containers/sound-tab.jsx
+++ b/src/containers/sound-tab.jsx
@@ -223,7 +223,8 @@ class SoundTab extends React.Component {
                     onClick: this.handleFileUploadClick,
                     fileAccept: '.wav, .mp3',
                     fileChange: this.handleSoundUpload,
-                    fileInput: this.setFileInput
+                    fileInput: this.setFileInput,
+                    fileMultiple: true
                 }, {
                     title: intl.formatMessage(messages.surpriseSound),
                     img: surpriseIcon,
diff --git a/src/lib/file-uploader.js b/src/lib/file-uploader.js
index 74f3c64a8625c05610c4e0d505484e56fc4a8600..483f31edf61c95a08d6aa38522df9eda52d0aac7 100644
--- a/src/lib/file-uploader.js
+++ b/src/lib/file-uploader.js
@@ -21,22 +21,25 @@ const extractFileName = function (nameExt) {
  * @param {Function} onload The function that handles loading the file
  */
 const handleFileUpload = function (fileInput, onload) {
-    let thisFile = null;
-    const reader = new FileReader();
-    reader.onload = () => {
-        // Reset the file input value now that we have everything we need
-        // so that the user can upload the same sound multiple times if
-        // they choose
-        fileInput.value = null;
-        const fileType = thisFile.type;
-        const fileName = extractFileName(thisFile.name);
-
-        onload(reader.result, fileType, fileName);
+    const readFile = (i, files) => {
+        if (i === files.length) {
+            // Reset the file input value now that we have everything we need
+            // so that the user can upload the same sound multiple times if
+            // they choose
+            fileInput.value = null;
+            return;
+        }
+        const file = files[i];
+        const reader = new FileReader();
+        reader.onload = () => {
+            const fileType = file.type;
+            const fileName = extractFileName(file.name);
+            onload(reader.result, fileType, fileName);
+            readFile(i + 1, files);
+        };
+        reader.readAsArrayBuffer(file);
     };
-    if (fileInput.files) {
-        thisFile = fileInput.files[0];
-        reader.readAsArrayBuffer(thisFile);
-    }
+    readFile(0, fileInput.files);
 };
 
 /**
diff --git a/test/fixtures/movie.wav b/test/fixtures/movie.wav
new file mode 100644
index 0000000000000000000000000000000000000000..79c10d2146204fa108038bc4a67c853ec81a4707
Binary files /dev/null and b/test/fixtures/movie.wav differ
diff --git a/test/fixtures/sneaker.wav b/test/fixtures/sneaker.wav
new file mode 100644
index 0000000000000000000000000000000000000000..01c4a17597b5e747368094e61c2e8d0d3414cc2b
Binary files /dev/null and b/test/fixtures/sneaker.wav differ
diff --git a/test/integration/backdrops.test.js b/test/integration/backdrops.test.js
index 9a527b2c9d4caa39287b9566af459648efb6ae7b..d0a3e84aa841f73309fb36c88019092e943b6a03 100644
--- a/test/integration/backdrops.test.js
+++ b/test/integration/backdrops.test.js
@@ -4,6 +4,7 @@ import SeleniumHelper from '../helpers/selenium-helper';
 const {
     clickText,
     clickXpath,
+    findByText,
     findByXpath,
     getDriver,
     getLogs,
@@ -49,4 +50,30 @@ describe('Working with backdrops', () => {
         const logs = await getLogs();
         await expect(logs).toEqual([]);
     });
+
+    test.only('Adding multiple backdrops at the same time', async () => {
+        const files = [
+            path.resolve(__dirname, '../fixtures/gh-3582-png.png'),
+            path.resolve(__dirname, '../fixtures/100-100.svg')
+        ];
+        await loadUri(uri);
+        await clickXpath('//button[@title="Try It"]');
+
+        const buttonXpath = '//button[@aria-label="Choose a Backdrop"]';
+        const fileXpath = `${buttonXpath}/following-sibling::div//input[@type="file"]`;
+
+        const el = await findByXpath(buttonXpath);
+        await driver.actions().mouseMove(el)
+            .perform();
+        await driver.sleep(500); // Wait for thermometer menu to come up
+        const input = await findByXpath(fileXpath);
+        await input.sendKeys(files.join('\n'));
+
+        await clickXpath('//span[text()="Stage"]');
+        await findByText('gh-3582-png', scope.costumesTab);
+        await findByText('100-100', scope.costumesTab);
+
+        const logs = await getLogs();
+        await expect(logs).toEqual([]);
+    });
 });
diff --git a/test/integration/costumes.test.js b/test/integration/costumes.test.js
index 5181c429a6b69cb0298f9eb677787c672c3ac8dd..803abbdafde5649a6de75157b500b6ce3fe0b649 100644
--- a/test/integration/costumes.test.js
+++ b/test/integration/costumes.test.js
@@ -4,6 +4,7 @@ import SeleniumHelper from '../helpers/selenium-helper';
 const {
     clickText,
     clickXpath,
+    findByText,
     findByXpath,
     getDriver,
     getLogs,
@@ -181,4 +182,25 @@ describe('Working with costumes', () => {
         await expect(logs).toEqual([]);
     });
 
+    test.only('Adding multiple costumes at the same time', async () => {
+        const files = [
+            path.resolve(__dirname, '../fixtures/gh-3582-png.png'),
+            path.resolve(__dirname, '../fixtures/100-100.svg')
+        ];
+        await loadUri(uri);
+        await clickXpath('//button[@title="Try It"]');
+        await clickText('Costumes');
+        const el = await findByXpath('//button[@aria-label="Choose a Costume"]');
+        await driver.actions().mouseMove(el)
+            .perform();
+        await driver.sleep(500); // Wait for thermometer menu to come up
+        const input = await findByXpath('//input[@type="file"]');
+        await input.sendKeys(files.join('\n'));
+
+        await findByText('gh-3582-png', scope.costumesTab);
+        await findByText('100-100', scope.costumesTab);
+
+        const logs = await getLogs();
+        await expect(logs).toEqual([]);
+    });
 });
diff --git a/test/integration/sounds.test.js b/test/integration/sounds.test.js
index 3877ada3f8fa90acb8e866418fcc5ff1425b516d..940e4750cbc17da4520646e4a29216cf47fd57a9 100644
--- a/test/integration/sounds.test.js
+++ b/test/integration/sounds.test.js
@@ -4,6 +4,7 @@ import SeleniumHelper from '../helpers/selenium-helper';
 const {
     clickText,
     clickXpath,
+    findByText,
     findByXpath,
     getDriver,
     getLogs,
@@ -114,4 +115,26 @@ describe('Working with sounds', () => {
         const logs = await getLogs();
         await expect(logs).toEqual([]);
     });
+
+    test.only('Adding multiple sounds at the same time', async () => {
+        const files = [
+            path.resolve(__dirname, '../fixtures/movie.wav'),
+            path.resolve(__dirname, '../fixtures/sneaker.wav')
+        ];
+        await loadUri(uri);
+        await clickXpath('//button[@title="Try It"]');
+        await clickText('Sounds');
+        const el = await findByXpath('//button[@aria-label="Choose a Sound"]');
+        await driver.actions().mouseMove(el)
+            .perform();
+        await driver.sleep(500); // Wait for thermometer menu to come up
+        const input = await findByXpath('//input[@type="file"]');
+        await input.sendKeys(files.join('\n'));
+
+        await findByText('movie', scope.soundsTab);
+        await findByText('sneaker', scope.soundsTab);
+
+        const logs = await getLogs();
+        await expect(logs).toEqual([]);
+    });
 });
diff --git a/test/integration/sprites.test.js b/test/integration/sprites.test.js
index a3dd48cf4a5e319fd8660276ed22330910eeca53..12ab36a5fb7bfd172585e4c4670e929a5b1ff7e4 100644
--- a/test/integration/sprites.test.js
+++ b/test/integration/sprites.test.js
@@ -159,4 +159,25 @@ describe('Working with sprites', () => {
         await expect(logs).toEqual([]);
     });
 
+    test.only('Adding multiple sprites at the same time', async () => {
+        const files = [
+            path.resolve(__dirname, '../fixtures/gh-3582-png.png'),
+            path.resolve(__dirname, '../fixtures/100-100.svg')
+        ];
+        await loadUri(uri);
+        await clickXpath('//button[@title="Try It"]');
+        const el = await findByXpath('//button[@aria-label="Choose a Sprite"]');
+        await driver.actions().mouseMove(el)
+            .perform();
+        await driver.sleep(500); // Wait for thermometer menu to come up
+        const input = await findByXpath('//input[@type="file"]');
+        await input.sendKeys(files.join('\n'));
+
+        await findByText('gh-3582-png', scope.spriteTile);
+        await findByText('100-100', scope.spriteTile);
+
+        const logs = await getLogs();
+        await expect(logs).toEqual([]);
+    });
+
 });