File upload
The File upload component allows users to attach one or multiple files to a form via drag-and-drop or by browsing their device.
import { ... } from '@ag.ds-next/react/file-upload';
() => { const [value, setValue] = React.useState(); return ( <FileUpload label="Upload documents" value={value} onChange={setValue} /> ); };
File upload is used in forms to enable users to upload files. Unlike File input it can be used to upload multiple files, restrict the number, types and size of files, plus much more. There are 2 ways to upload – via drag and drop or by browsing the device.
FileUpload
is a controlled component.
Do
- upload selected files instantly as they are selected or on submission
- specify accepted file types, maximum file size and whether the user can upload one file at a time or several at once
- include hint text to provide more general information about the field/file
- indicate file uploading state
- Make use of the ‘instant upload’ pattern if your backend supports it
- Consider the ‘simple download’ pattern for small screens
Don’t
- add a standalone Submit file button inside a form
- include other unrelated fields on the page
- use in modals or page alerts
- change the default behaviour of the component by adding a standalone upload file button.
Multiple files
Selecting multiple files is also supported with FileUpload. Simply add multiple={true}
, and you can select as many files as you want. You can also set maxFiles
to limit how many files can be selected.
() => { const [value, setValue] = React.useState(); return ( <FileUpload label="Upload files" hint="Upload a maximum of three files" value={value} onChange={setValue} multiple={true} maxFiles={2} maxSize={200} accept={['image/jpeg', 'image/png']} /> ); };
Maximum file size
Use the maxSize
prop to set a maximum size for each file. This value is measured in kilobytes (kB).
<FileUpload maxSize={200} /> // 200kB<FileUpload maxSize={20000} /> // 20MB
Accepted files
Use the accept
prop to specify what file types are allowed to be selected.
For a complete list allowed file formats, please refer to the source code.
<FileUpload label="Upload image" accept={['image/jpeg', 'image/png']} />
Custom accepted file types
If the file type you need to support isn’t in the list of allowed file formats, you can pass in your own file type to the accept
prop.
This can be done by passing an object instead of a string with mimeType
and extensions
as keys. Optionally, a label
key can be used for the summary inside of the component. By default, the label will be generated using the file extension.
<FileUpload label="Upload JavaScript file" accept={[{ mimeType: 'text/javascript', extensions: ['.js'] }]}/>
Hiding thumbnails
By default, the FileUpload
component will render a preview of every selected file.
To disable this behaviour, set the hideThumbnails
prop to true
.
<FileUpload hideThumbnails={true} />
Indicating upload status
When using FileUpload, you need to consider how to communicate to the user that the upload is in progress. Otherwise the page will appear ‘frozen’ as the operation happens in the background.
Uploading on submission
In this example, we are submitting a file as part of a typical form submission to an API.
We recommend using a LoadingBlanket component as the form submits to indicate to the user that any delays are being caused by a potentially larger file being uploaded. If your backend system supports it, you can also use this UI to indicate upload status as a percentage.
As normal, we indicate that the form is submitting by adding a loading={true}
to the submit button. This will show animated dots to signify that the user has to wait for the operation to complete.
<FormStack> <div style={{ position: 'relative' }}> <FileUpload label="Upload documents" multiple={false} /> <LoadingBlanket label="Uploading file (53%)" /> </div> <div> <Button loading={true}>Submit</Button> </div> </FormStack>
Uploading files instantly
In this example, the file is instantly uploaded to a file hosting service, and the URL of the uploaded asset would be added to the form for submission. This means the form should not be allowed to submit until all assets are uploaded, but that the submission should be very quick as it’s only text content being submitted.
FileUpload
component allows you to indicate the status of an upload via a file.status
property.
() => { const uploadedFile = createExampleImageFile({ status: 'success' }); const uploadingFile = createExampleFile({ status: 'uploading' }); const [value, setValue] = React.useState([uploadedFile, uploadingFile]); function onChange(files) { setValue( files.map((file) => { file.status = file.status || 'uploading'; return file; }) ); // Show uploaded state after simulated network request setTimeout(() => { setValue( files.map((file) => { if (file.status == 'uploading') { file.status = 'success'; } return file; }) ); }, 1500); } return ( <FileUpload label="Upload documents" multiple={true} value={value} onChange={onChange} /> ); };
Existing files
You can display a list of files that have already been uploaded by using the existingFiles
and onRemoveExistingFile
props.
Unlike the value
prop, which expects an array of File
objects, existingFiles
expects an array of objects with a name, size and thumbnail url.
If a user attempts to delete an existing file, a destructive confirmation modal should be displayed. If confirmed, the file should be deleted on the server.
Image files should be displayed with thumbnails which are 72px by 72px. Passing full-size images to thumbnailSrc
prop will result with long load times.
() => { const [existingFiles, setExistingFiles] = useState([ { name: 'example.png', size: 123456, thumbnailSrc: 'https://via.placeholder.com/150', href: '#', // Use the meta key to keep track of any extra file info // This can be useful info when deleting the file meta: { uid: 'abc-def', bucketId: '123-456' }, }, { name: 'example-no-thumbnail.doc', size: 654321, href: '#', // Use the meta key to keep track of any extra file info // This can be useful info when deleting the file meta: { uid: 'fed=cba', bucketId: '654-321' }, }, ]); function onRemoveExistingFile(fileToRemove) { setExistingFiles((existingFiles) => existingFiles.filter((file) => file.meta.uid !== fileToRemove.meta.uid) ); } const [value, setValue] = React.useState(); return ( <FileUpload label="Upload documents" multiple={true} value={value} onChange={setValue} existingFiles={existingFiles} onRemoveExistingFile={onRemoveExistingFile} /> ); };
Required
The required
prop can be used to indicate that user input is required on the field before a form can be submitted.
Required fields do not append ‘(optional)’ to the label and also use aria-required to indicate to screen readers that the field is required.
Hide optional label
The hideOptionalLabel
prop can be used in situations where you want to indicate to screen reader users that a field is optional but don’t want to show the ‘(optional)’ label.
Invalid
Use the invalid
prop to indicate if the user input is invalid.
() => { const [value, setValue] = React.useState([]); return ( <FileUpload label="Upload a file" value={value} onChange={setValue} invalid={value.length === 0} required={true} message="Select a file" /> ); };
Related components
- File input – The File input component allows users to attach one file to a form field by browsing their device.