diff --git a/app/components/component-submit/src/components/SubmitPage.js b/app/components/component-submit/src/components/SubmitPage.js
index c510504b92d171e1d410ae6b3df910f63d339f59..1ba8a7c7f318eedbe64dfdd28069db0288e7449b 100644
--- a/app/components/component-submit/src/components/SubmitPage.js
+++ b/app/components/component-submit/src/components/SubmitPage.js
@@ -153,7 +153,7 @@ const SubmitPage = ({ match, history, ...props }) => {
 
   const [createFile] = useMutation(createFileMutation)
 
-  const createSupplementaryFile = file => {
+  const createSupplementaryFile = async file => {
     const meta = {
       filename: file.name,
       mimeType: file.type,
@@ -163,12 +163,13 @@ const SubmitPage = ({ match, history, ...props }) => {
       objectId: match.params.version,
     }
 
-    createFile({
+    const { data } = await createFile({
       variables: {
         file,
         meta,
       },
     })
+    return data
   }
 
   const [update] = useMutation(updateMutation)
diff --git a/app/components/component-submit/src/components/Supplementary.js b/app/components/component-submit/src/components/Supplementary.js
index 0432c9488da0896b8e7e21522fc7629516d82cc2..68b89629614c478069428d1d7c8f0e64ea38b868 100644
--- a/app/components/component-submit/src/components/Supplementary.js
+++ b/app/components/component-submit/src/components/Supplementary.js
@@ -1,30 +1,33 @@
 import React from 'react'
 import { cloneDeep } from 'lodash'
 import { FieldArray } from 'formik'
-import { Flexbox, UploadButton, UploadingFile } from '@pubsweet/ui'
+import { Flexbox } from '@pubsweet/ui'
+import styled from 'styled-components'
+import UploadingFile from './UploadingFile'
+import { Dropzone } from '../../../shared'
 
-const renderFilesUpload = (onChange, createSupplementaryFile) => ({
+const Root = styled.div``
+const renderFilesUpload = createSupplementaryFile => ({
   form: { values, setFieldValue },
   push,
   insert,
 }) => (
   <>
-    <UploadButton
-      buttonText="↑ Upload files"
-      onChange={event => {
-        const fileArray = Array.from(event.target.files).map(file => {
-          const fileUpload = {
-            fileType: 'supplementary',
-            filename: file.name,
-          }
-          return fileUpload
-        })
-        setFieldValue('files', fileArray.concat(values.files))
-        Array.from(event.target.files).forEach(file => {
-          createSupplementaryFile(file)
+    <Dropzone
+      onDrop={async files => {
+        Array.from(files).forEach(async file => {
+          const data = await createSupplementaryFile(file)
+          push(data.createFile)
         })
       }}
-    />
+    >
+      {({ getRootProps, getInputProps }) => (
+        <Root {...getRootProps()}>
+          <input {...getInputProps()} />
+          <p>Your files here</p>
+        </Root>
+      )}
+    </Dropzone>
     <Flexbox>
       {cloneDeep(values.files || [])
         .filter(val => val.fileType === 'supplementary')
@@ -36,10 +39,10 @@ const renderFilesUpload = (onChange, createSupplementaryFile) => ({
   </>
 )
 
-const Supplementary = ({ onChange, createSupplementaryFile }) => (
+const Supplementary = ({ createSupplementaryFile }) => (
   <FieldArray
     name="files"
-    render={renderFilesUpload(onChange, createSupplementaryFile)}
+    render={renderFilesUpload(createSupplementaryFile)}
   />
 )
 
diff --git a/app/components/component-submit/src/components/UploadButton.js b/app/components/component-submit/src/components/UploadButton.js
new file mode 100644
index 0000000000000000000000000000000000000000..fb6c96449dceff7ad115457742617e4072406a7d
--- /dev/null
+++ b/app/components/component-submit/src/components/UploadButton.js
@@ -0,0 +1,33 @@
+import React from 'react'
+import styled from 'styled-components'
+import { th } from '@pubsweet/ui-toolkit'
+
+const Button = styled.button.attrs(() => ({
+  type: 'button',
+}))`
+  background: transparent;
+  border: ${th('borderWidth')} dashed ${th('colorBorder')};
+  height: calc(${th('gridUnit')} * 3);
+  cursor: pointer;
+  margin-bottom: calc(${th('gridUnit')} * 3);
+  padding: ${th('gridUnit')};
+`
+
+const UploadButton = ({ name, buttonText, onChange }) => {
+  let fileInput
+  return (
+    <React.Fragment>
+      <Button onClick={() => fileInput.click()}>{buttonText}</Button>
+      <input
+        multiple
+        name={name}
+        onChange={onChange}
+        ref={input => (fileInput = input)}
+        style={{ display: 'none' }}
+        type="file"
+      />
+    </React.Fragment>
+  )
+}
+
+export default UploadButton
diff --git a/app/components/component-submit/src/components/UploadManuscript.js b/app/components/component-submit/src/components/UploadManuscript.js
index cdb5e7e0bed5cceb05818b51c8313b0736ebd587..807e004c4350ab54642dd32e46261722fb931738 100644
--- a/app/components/component-submit/src/components/UploadManuscript.js
+++ b/app/components/component-submit/src/components/UploadManuscript.js
@@ -2,17 +2,9 @@ import React, { useContext } from 'react'
 import styled, { keyframes, withTheme } from 'styled-components'
 import { Icon, Action } from '@pubsweet/ui'
 import { th } from '@pubsweet/ui-toolkit'
-import Dropzone from 'react-dropzone'
 import { XpubContext } from '../../../xpub-with-context/src'
 import upload from '../upload'
-
-const StyledDropzone = styled(({ disableUpload, ...props }) => (
-  <Dropzone {...props} />
-))`
-  border: none;
-  cursor: pointer;
-  ${({ disableUpload }) => disableUpload && 'pointer-events: none;'};
-`
+import { Dropzone } from '../../../shared'
 
 const StatusIcon = withTheme(({ children, theme }) => (
   <Icon color={theme.colorPrimary}>{children}</Icon>
@@ -188,7 +180,7 @@ const UploadManuscript = ({ acceptFiles, ...props }) => {
 
   return (
     <>
-      <StyledDropzone
+      <Dropzone
         accept={acceptFiles}
         data-testid="dropzone"
         disableUpload={converting ? 'disableUpload' : null}
@@ -222,7 +214,7 @@ const UploadManuscript = ({ acceptFiles, ...props }) => {
             </SubInfo>
           </Root>
         )}
-      </StyledDropzone>
+      </Dropzone>
       <Action onClick={() => uploadManuscript()}>Submit a URL instead</Action>
     </>
   )
diff --git a/app/components/component-submit/src/components/UploadingFile.js b/app/components/component-submit/src/components/UploadingFile.js
new file mode 100644
index 0000000000000000000000000000000000000000..c3d3b6628b9ff57578d4bfe1f512065677fe9bc9
--- /dev/null
+++ b/app/components/component-submit/src/components/UploadingFile.js
@@ -0,0 +1,141 @@
+import React from 'react'
+import styled from 'styled-components'
+import { th } from '@pubsweet/ui-toolkit'
+
+const Icon = styled.div`
+  background: ${th('colorFurniture')};
+  height: calc(${th('gridUnit')} * 15);
+  margin-bottom: ${th('gridUnit')};
+  opacity: 0.5;
+  position: relative;
+  width: calc(${th('gridUnit')} * 9);
+`
+
+const Progress = styled.div`
+  color: ${th('colorTextReverse')};
+  display: block;
+  position: absolute;
+  bottom: ${th('gridUnit')};
+  left: calc(${th('gridUnit')} * 4);
+`
+
+const Extension = styled.div`
+  background: ${th('colorText')};
+  color: ${th('colorTextReverse')};
+  font-size: ${th('fontSizeBaseSmall')};
+  line-height: ${th('lineHeightBaseSmall')};
+  left: calc(${th('gridUnit')} * 2);
+  position: absolute;
+  right: 0;
+  text-align: center;
+  text-transform: uppercase;
+  top: calc(${th('gridUnit')} * 2);
+`
+
+const Filename = styled.div`
+  color: ${th('colorText')};
+  font-size: ${th('fontSizeBaseSmall')};
+  line-height: ${th('lineHeightBaseSmall')};
+  font-style: italic;
+  max-width: calc(${th('gridUnit')} * 30);
+`
+
+const Uploading = styled.div`
+  align-items: center;
+  display: inline-flex;
+  flex-direction: column;
+  margin-bottom: calc(${th('gridUnit')} * 3);
+  margin-right: calc(${th('gridUnit')} * 3);
+  position: relative;
+  width: calc(${th('gridUnit')} * 30);
+`
+
+const Uploaded = styled(Uploading)`
+  &::before,
+  &::after {
+    cursor: pointer;
+    transition: transform ${th('transitionDuration')};
+    font-size: ${th('fontSizeBaseSmall')};
+    line-height: ${th('lineHeightBaseSmall')};
+    left: 65%;
+    padding: 0 ${th('gridUnit')} 0 ${th('gridUnit')};
+    position: absolute;
+    border: ${th('borderWidth')} ${th('borderStyle')} ${th('colorTextReverse')};
+    color: ${th('colorTextReverse')};
+    text-transform: uppercase;
+    transform: scaleX(0);
+    transform-origin: 0 0;
+  }
+
+  &::after {
+    background: ${th('colorError')};
+    content: 'Remove';
+    top: calc(${th('gridUnit')} * 5);
+    z-index: 2;
+  }
+
+  &::before {
+    background: ${th('colorPrimary')};
+    content: 'Replace';
+    top: calc(${th('gridUnit')} * 10);
+    z-index: 3;
+  }
+
+  &:hover ${Extension} {
+    background: ${th('colorTextReverse')};
+    color: ${th('colorPrimary')};
+  }
+
+  &:hover ${Icon} {
+    opacity: 1;
+    background: ${th('colorPrimary')};
+    transform: skewY(6deg) rotate(-6deg);
+  }
+
+  &:hover::after,
+  &:hover::before {
+    transform: scaleX(1);
+  }
+`
+
+const ErrorWrapper = styled.div`
+  background: ${th('colorError')};
+  border: calc(${th('borderWidth')} * 2) ${th('borderStyle')}
+    ${th('colorTextReverse')};
+  color: ${th('colorTextReverse')};
+  font-size: ${th('fontSizeBaseSmall')};
+  line-height: ${th('lineHeightBaseSmall')};
+  letter-spacing: 0.01em;
+  opacity: 1;
+  padding: ${th('gridUnit')} ${th('gridUnit')};
+  position: absolute;
+  top: 25%;
+  z-index: 4;
+`
+
+const getFileExtension = ({ name }) => name.replace(/^.+\./, '')
+
+const UploadingFile = ({ file, progress, error, uploaded }) => {
+  const Root = uploaded ? Uploaded : Uploading
+
+  return (
+    <Root>
+      {!!error && <ErrorWrapper>{error}</ErrorWrapper>}
+      <Icon>
+        {!!progress && <Progress>{progress * 100}%</Progress>}
+        <Extension>{getFileExtension(file)}</Extension>
+      </Icon>
+      <Filename>
+        {uploaded ? (
+          <a download={file.name} href={file.url}>
+            {file.name}
+          </a>
+        ) : (
+          file.name
+        )}
+      </Filename>
+    </Root>
+  )
+}
+
+export default UploadingFile
diff --git a/app/components/shared/Dropzone.jsx b/app/components/shared/Dropzone.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..29f979895c8b23e1da7ae91c4551ecc3737c6a7c
--- /dev/null
+++ b/app/components/shared/Dropzone.jsx
@@ -0,0 +1,11 @@
+import React from 'react'
+import styled from 'styled-components'
+import ReactDropzone from 'react-dropzone'
+
+export const Dropzone = styled(({ disableUpload, ...props }) => (
+  <ReactDropzone {...props} />
+))`
+  border: none;
+  cursor: pointer;
+  ${({ disableUpload }) => disableUpload && 'pointer-events: none;'};
+`
diff --git a/app/components/shared/index.js b/app/components/shared/index.js
index 9c03d0839662980df9d89035eb141a227f8a089b..62ccca06d70da3fdf4956ae870a9c8b11b4f45f9 100644
--- a/app/components/shared/index.js
+++ b/app/components/shared/index.js
@@ -8,3 +8,4 @@ export * from './Table'
 export * from './General'
 export * from './Badge'
 export * from './Select'
+export * from './Dropzone'