Multiple file upload is able to:
- Accept one or more files via browse or drag-and-drop
- Provide their data to you using file objects via the
onFileDrop
callback prop - Read files as dataURLs, calling provided callbacks as needed when files start/finish being read, as well as when the read succeeds or fails
- Display (in real time) the upload progress/status of each file
- Uploaded files are represented by the multiple file upload status item component, this component includes the aforementioned built-in file reading logic
- If you prefer to supply your own file reading logic and strictly use multiple file upload status item as a display component, the
customFileHandler
,fileName
,fileSize
,progressValue
, andprogressVariant
props exist to allow you to do that
Restricting file size and type
As with singular file upload, any props accepted by react-dropzone's Dropzone component can be passed as a dropzoneProps object in order to customize the behavior of the Dropzone, such as restricting the type of files allowed. The following examples will only accept the files they list as accepted. Note that file type determination is not reliable across platforms (see the note on react-dropzone's docs about the accept prop), so be sure to test the behavior of your file upload restriction on all browsers and operating systems targeted by your application.
IMPORTANT: A note about security
Restricting file sizes and types in this way is for user convenience only, and it cannot prevent a malicious user from submitting anything to your server. As with any user input, your application should also validate, sanitize and/or reject restricted files on the server side.
Composable structure
File upload - multiple is designed in a composable manner to make customization easier. The standard sub-component relationships are arranged as follows:
<MultipleFileUpload>
<MultipleFileUploadMain />
<MultipleFileUploadStatus>
<MultipleFileUploadStatusItem />
</MultipleFileUploadStatus>
</MultipleFileUpload>
Examples
Basic
The below example demonstrates a typical application of file upload - multiple, with a few tweaks from that typical application to enhance the convenience of the example.
The "Show as horizontal" checkbox can be used to easily toggle the isHorizontal
prop, showing our available styling variations.
The "Demonstrate error reporting by forcing uploads to fail" checkbox shows how our progressHelperText
prop can be used to provide status messages to users, such as when a file fails to upload. While this checkbox is checked it will cause any file uploaded to automatically fail the file reading process, and helper text will be dynamically rendered which informs the user of that error.
Types
Multiple file upload uses the DropzoneOptions
type from react-dropzone. It is comprised of additional props with their own types. For more information on using DropzoneOptions
visit react-dropzone props and methods.
Additionally, it calls the onFileDrop
callback with an event of type DropEvent
. DropEvent
is a union comprised of the following types:
React.DragEvent<HTMLElement>
| React.ChangeEvent<HTMLInputElement>
| DragEvent
| Event
Props
MultipleFileUpload
Name | Type | Default | Description |
---|---|---|---|
children | React.ReactNode | Content rendered inside the multi upload field | |
className | string | Class to add to outer div | |
dropzoneProps | DropzoneOptions | {} | Optional extra props to customize react-dropzone. |
isHorizontal | boolean | Flag setting the component to horizontal styling mode | |
onFileDrop | (event: DropEvent, data: File[]) => void | () => {} | When files are dropped or uploaded this callback will be called with all accepted files |
MultipleFileUploadMain
Name | Type | Default | Description |
---|---|---|---|
browseButtonText | string | 'Upload' | Visible text label for the upload button |
className | string | Class to add to outer div | |
infoText | React.ReactNode | Content rendered inside the info div | |
isUploadButtonHidden | boolean | Flag to prevent the upload button from being rendered | |
titleIcon | React.ReactNode | Content rendered inside the title icon div | |
titleText | React.ReactNode | Content rendered inside the title text div | |
titleTextSeparator | React.ReactNode | Content rendered inside the title text separator div |
MultipleFileUploadStatus
Name | Type | Default | Description |
---|---|---|---|
aria-label | string | Adds an accessible label to the list of status items. | |
children | React.ReactNode | Content rendered inside multi file upload status list | |
className | string | Class to add to outer div | |
statusToggleIcon | 'danger' | 'success' | 'inProgress' | React.ReactNode | Icon to show in the status toggle | |
statusToggleText | string | String to show in the status toggle |
MultipleFileUploadStatusItem
Name | Type | Default | Description |
---|---|---|---|
buttonAriaLabel | string | 'Remove from list' | Adds accessibility text to the status item deletion button |
className | string | Class to add to outer div | |
customFileHandler | (file: File) => void | A callback to process file reading in a custom way | |
file | File | The file object being represented by the status item | |
fileIcon | React.ReactNode | A custom icon to show in place of the generic file icon | |
fileName | string | A custom name to display for the file rather than using built in functionality to auto-fill it | |
fileSize | number | A custom file size to display for the file rather than using built in functionality to auto-fill it | |
onClearClick | React.MouseEventHandler<HTMLButtonElement> | () => {} | Clear button was clicked |
onReadFail | (error: DOMException, onReadFail: File) => void | () => {} | A callback for when the FileReader API fails |
onReadFinished | (fileHandle: File) => void | () => {} | A callback for when a selected file finishes loading |
onReadStarted | (fileHandle: File) => void | () => {} | A callback for when a selected file starts loading |
onReadSuccess | (data: string, file: File) => void | () => {} | A callback for when the FileReader successfully reads the file |
progressAriaLabel | string | Adds accessible text to the progress bar. Required when title not used and there is not any label associated with the progress bar | |
progressAriaLabelledBy | string | Associates the progress bar with it's label for accessibility purposes. Required when title not used | |
progressAriaLiveMessage | string | ((loadPercentage: number) => string) | Modifies the text announced by assistive technologies when the progress bar updates. | |
progressHelperText | React.ReactNode | Additional content related to the status item. | |
progressId | string | Unique identifier for progress. Generated if not specified. | |
progressValue | number | A custom value to display for the progress component rather than using built in functionality to auto-fill it | |
progressVariant | 'danger' | 'success' | 'warning' | A custom variant to apply to the progress component rather than using built in functionality to auto-fill it |
CSS variables
Expand or collapse column | Selector | Variable | Value | |
---|---|---|---|---|
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--GridTemplateColumns | 1fr | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--Gap | 1rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__main--TextAlign | center | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__main--GridTemplateColumns | auto | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__main--GridTemplateRows | auto | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__main--GridTemplateAreas | "title"
"upload"
"info" | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__main--PaddingBlockStart | 2rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__main--PaddingInlineEnd | 2rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__main--PaddingBlockEnd | 2rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__main--PaddingInlineStart | 2rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__main--BorderWidth | 1px | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__main--BorderStyle | dashed | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__main--BorderColor | (In light theme) #c7c7c7 | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__main--BorderRadius | 16px | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title--Display | grid | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title--GridTemplateColumns | auto | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title--Gap | 1.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-text--Color | (In light theme) #151515 | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-text--FontFamily | "Red Hat Display", "RedHatDisplay", "Noto Sans Arabic", "Noto Sans Hebrew", "Noto Sans JP", "Noto Sans KR", "Noto Sans Malayalam", "Noto Sans SC", "Noto Sans TC", "Noto Sans Thai", Helvetica, Arial, sans-serif | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-text--FontSize | 1.125rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-text--FontWeight | 500 | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-icon--Color | (In light theme) #1f1f1f | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-icon--FontSize | 1.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-text-separator--Display | block | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-text-separator--MarginBlockStart | 0.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-text-separator--MarginBlockEnd | 0.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-text-separator--Color | (In light theme) #151515 | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-text-separator--FontFamily | "Red Hat Text", "RedHatText", "Noto Sans Arabic", "Noto Sans Hebrew", "Noto Sans JP", "Noto Sans KR", "Noto Sans Malayalam", "Noto Sans SC", "Noto Sans TC", "Noto Sans Thai", Helvetica, Arial, sans-serif | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-text-separator--FontSize | 1rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__title-text-separator--FontWeight | 400 | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__info--FontSize | 0.875rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__info--Color | (In light theme) #4d4d4d | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__info--MarginBlockStart | 1.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-drag-over__main--BorderStyle | dashed | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-drag-over__main--BorderColor | (In light theme) #0066cc | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal--GridTemplateColumns | fit-content(100%) | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__main--TextAlign | start | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__main--GridTemplateColumns | 1fr auto | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__main--GridTemplateAreas | "title upload"
"info upload" | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__main--Gap | 0.5rem 1.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__main--PaddingBlockEnd | 1.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__title--GridTemplateColumns | auto 1fr | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__title--Gap | 0.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__title-icon--FontSize | 1rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__title-text--FontSize | 1rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__title-text-separator--Display | inline | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__title-text-separator--MarginBlockStart | 0 | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__title-text-separator--FontFamily | "Red Hat Display", "RedHatDisplay", "Noto Sans Arabic", "Noto Sans Hebrew", "Noto Sans JP", "Noto Sans KR", "Noto Sans Malayalam", "Noto Sans SC", "Noto Sans TC", "Noto Sans Thai", Helvetica, Arial, sans-serif | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__title-text-separator--FontSize | 1rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__title-text-separator--FontWeight | 500 | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload--m-horizontal__info--MarginBlockStart | 0 | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status--PaddingBlockStart | 0.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status--PaddingBlockEnd | 0.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status--PaddingInlineStart | 1rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status--PaddingInlineEnd | 1rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-progress--GridTemplateColumns | auto 1fr | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-progress--Gap | 0.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-progress-icon--Color | (In light theme) #0066cc | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-item--PaddingBlockStart | 1rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-item--PaddingBlockEnd | 1rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-item--GridTemplateColumns | auto 1fr auto | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-item--Gap | 0.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-item--BorderWidth | 1px | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-item--BorderColor | (In light theme) #c7c7c7 | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-item-icon--Color | (In light theme) #1f1f1f | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-item-progress--GridTemplateColumns | fit-content(100%) max-content | ||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-item-progress--Gap | 0.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-item-progress-text--Color | (In light theme) #151515 | ||
| ||||
.pf-v6-c-multiple-file-upload | --pf-v6-c-multiple-file-upload__status-item-progress-size--Color | (In light theme) #4d4d4d | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload--GridTemplateColumns | fit-content(100%) | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__main--TextAlign | start | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__main--GridTemplateColumns | 1fr auto | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__main--GridTemplateAreas | "title upload"
"info upload" | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__main--Gap | 0.5rem 1.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__main--PaddingBlockEnd | 1.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__title--GridTemplateColumns | auto 1fr | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__title--Gap | 0.5rem | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__title-icon--FontSize | 1rem | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__title-text--FontSize | 1rem | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__title-text-separator--FontFamily | "Red Hat Display", "RedHatDisplay", "Noto Sans Arabic", "Noto Sans Hebrew", "Noto Sans JP", "Noto Sans KR", "Noto Sans Malayalam", "Noto Sans SC", "Noto Sans TC", "Noto Sans Thai", Helvetica, Arial, sans-serif | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__title-text-separator--Display | inline | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__title-text-separator--MarginBlockStart | 0 | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__title-text-separator--FontSize | 1rem | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__title-text-separator--FontWeight | 500 | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-horizontal | --pf-v6-c-multiple-file-upload__info--MarginBlockStart | 0 | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-drag-over | --pf-v6-c-multiple-file-upload__main--BorderStyle | dashed | ||
| ||||
.pf-v6-c-multiple-file-upload.pf-m-drag-over | --pf-v6-c-multiple-file-upload__main--BorderColor | (In light theme) #0066cc | ||
|