Amplify UI

FileUploader

The FileUploader lets your users upload and manage files in the cloud.


Drop files here or

Basic Usage

Next.js 13.4+ introduces App Router with the usage of Server Components. Amplify UI components are interactive and designed to work on the client side. To use them inside of Server Components you must wrap them in a Client Component with "use client". For more info, visit Next.js third party package documentation.

If you are using Next.js Pages Router, no changes are required to use Amplify UI components.

To use the FileUploader component import it into your React application with the included styles.

npm install @aws-amplify/ui-react-storage aws-amplify
yarn add @aws-amplify/ui-react-storage aws-amplify
import { FileUploader } from '@aws-amplify/ui-react-storage';
import '@aws-amplify/ui-react/styles.css';

At a minimum you must include the path and maxFileCount props. path refers to the S3 image path that will be prefixed to each file key. It is either a string or a callback function that accepts the current user's Cognito identityId and returns a string. See upload files

Drop files here or

import { FileUploader } from '@aws-amplify/ui-react-storage';

export const App = () => {
  return (
    <FileUploader
      acceptedFileTypes={['image/*']}
      path="public/"
      maxFileCount={1}
      isResumable
    />
  );
};

Private or Protected Buckets

When uploading to private or protected S3 buckets, you'll need to wrap your app in the Authenticator, allowing the FileUploader component to infer the Cognito identityId of the currently signed-in user. This can be done directly with the Authenticator component or with withAuthenticator, as shown in Add the Authenticator.

The example below shows configuring the FileUploader to upload to the protected folder under the users' identity id.

<FileUploader
  acceptedFileTypes={['image/*']}
  path={({ identityId }) => `protected/${identityId}/`}
  maxFileCount={1}
  isResumable
/>

Deprecated props

Using @aws-amplify/ui-react-storage version 3.0.18 or below?

Versions 3.0.18 and earlier use accessLevel and an optional path prop in place of the required path. accessLevel refers to the Amplify Storage access level, which is 'guest' | 'protected' | 'private', and path is a string.

<StorageManager
  accessLevel="guest"
  path="images/"
  maxFileCount={1}
/>
<StorageManager
  accessLevel="private"
  maxFileCount={1}
/>

To migrate to a newer version, replace accessLevel with path. If you were using path already, append public, private or protected to the beginning of the path.

  <StorageManager
-   accessLevel="guest"
+   path="public/"
    maxFileCount={1}
  />
  <StorageManager
-   accessLevel="private"
-   path="images/"
+   path={({ identityId }) => `private/${identityId}/images/`}
    maxFileCount={1}
  />

Props

NameDescriptionType
pathS3 bucket key prefixed to each upload target file `key`, allows either a `string` or a callback provided the value of the current user's `identityId`.
string | (input: { identityId: string | undefined }) => string
path?Optional when `accessLevel` is provided. S3 bucket key prefixed to each upload target file `key`
string
accessLevelDeprecated in favor of `path`. S3 access level of upload target files. See https://docs.amplify.aws/gen1/react/build-a-backend/storage/configure-access/
'guest' | 'protected' | 'private'
acceptedFileTypes?List of accepted file types, values of `['*']` or undefined allow any files
string[]
autoUpload?Determines if the upload will automatically start after a file is selected. The default value is `true`
boolean
maxFileCount
integer
maxFileSize?
integer
onUploadStart?Called when a file starts uploading
(file: {key: string}) => void;
onUploadSuccess?Called when a file successfully uploads
(file: {key: string}) => void;
onUploadError?Called when a error happens uploading a file
(error: string, file: {key: string}) => void;
onFileRemove?Called when a file is removed
(file: {key: string}) => void;
processFile?Called immediately before uploading a file to allow you to edit the key or the file itself. The function can return synchronously or return a promise.
(params: {key: string, file: Blob}) => Promise<{key: string, file: Blob} & Record<string, any>> | {key: string, file: Blob} & Record<string, string>;
defaultFiles?An array of files that already exist in the cloud.
Array<{s3key: string}>
displayText?Text to override in the component.
FileUploaderDisplayText
useAccelerateEndpoint?Use the accelerated S3 endpoint to upload files.
boolean
components?.Container?The container the FileUploader is wrapped in.
React.ComponentType<ContainerProps>
components?.DropZone?The dropzone element which contains the FilePicker
React.ComponentType<DropZoneProps>
components?.FilePicker?The button that opens the file picker menu.
React.ComponentType<FilePickerProps>
components?.FileList?The list of files that is being uploaded.
React.ComponentType<FileListProps>
components?.FileListHeader?The heading above the list of files
React.ComponentType<FileListHeaderProps>
components?.FileListFooter?The footer below the list of files
React.ComponentType<FileListFooterProps>
ref?Forward ref prop exposing FileUploader imperative methods.
React.ForwardedRef<FileUploaderHandle>

Manually Upload

The default behavior of the File Uploader component is to automatically start the upload after a file is selected. If you wish to change that, set the value of the autoUpload prop to false.

Drop files here or

import { FileUploader } from '@aws-amplify/ui-react-storage';

export const App = () => {
  return (
    <FileUploader
      acceptedFileTypes={['image/*']}
      path="public/"
      autoUpload={false}
      maxFileCount={1}
      isResumable
    />
  );
};

Setting Limits

You can limit what users upload with these 3 props:

  • maxFileSize: sets a maximum file size the uploader will accept in bytes. The default is unlimited.
  • maxFileCount: accepts how many files at one time you can select to upload.
  • acceptedFileTypes: an array of file type strings that follow the HTML accept attribute.

Drop files here or

import { FileUploader } from '@aws-amplify/ui-react-storage';

export const App = () => {
  return (
    <FileUploader
      acceptedFileTypes={[
        // you can list file extensions:
        '.gif',
        '.bmp',
        '.doc',
        '.jpeg',
        '.jpg',
        // or MIME types:
        'image/png',
        'video/*',
      ]}
      path="public/"
      maxFileCount={5}
      // Size is in bytes
      maxFileSize={10000}
    />
  );
};

Pausable / Resumable Uploads

A resumable upload will upload the file in chunks. This allows users to pause an upload and resume it at a later time. You will typically want to do this only when the expected files are larger than the chunk size, which is 5MB.

Drop files here or

import { FileUploader } from '@aws-amplify/ui-react-storage';

export const App = () => {
  return (
    <FileUploader
      acceptedFileTypes={['image/*', '.zip', '.mp4']}
      path="public/"
      maxFileCount={10}
      isResumable
    />
  );
};

Pre-upload Processing

You might want to process or modify the file(s) and/or file name(s) before they are uploaded. One common situation is you may want to ensure files uploaded are at unique keys by hashing the file contents and using that as the key rather than the filename.

You can pass a processFile function to the FileUploader which accepts an object with file: File, and key: string, and should return an object with file, key, and any other Storage configurations. The processFile can either return synchronously or return a Promise. This example uses a Promise to read the contents of the file and create a hash for the key.

Drop files here or

import { FileUploader } from '@aws-amplify/ui-react-storage';

const processFile = async ({ file }) => {
  const fileExtension = file.name.split('.').pop();

  return file
    .arrayBuffer()
    .then((filebuffer) => window.crypto.subtle.digest('SHA-1', filebuffer))
    .then((hashBuffer) => {
      const hashArray = Array.from(new Uint8Array(hashBuffer));
      const hashHex = hashArray
        .map((a) => a.toString(16).padStart(2, '0'))
        .join('');
      return { file, key: `${hashHex}.${fileExtension}` };
    });
};

export const App = () => {
  return (
    <FileUploader
      acceptedFileTypes={['image/*']}
      path="public/"
      maxFileCount={1}
      processFile={processFile}
    />
  );
};

Other uses-cases for processing the file before upload:

  1. Performing file optimizations like removing unnecessary metadata.
  2. Performing custom file validations like reading the contents of a file to ensure it is in the proper structure.

You can also add any other Amplify Storage options by adding them to the return object of processFile

Event Handling

The FileUploader component has several event handlers: onUploadStart, onUploadSuccess, onUploadError, and onFileRemove

Drop files here or

import * as React from 'react';
import { FileUploader } from '@aws-amplify/ui-react-storage';

export const App = () => {
  const [files, setFiles] = React.useState({});

  return (
    <>
      <FileUploader
        acceptedFileTypes={['image/*']}
        path={({ identityId }) => `private/${identityId}/`}
        maxFileCount={3}
        onFileRemove={({ key }) => {
          setFiles((prevFiles) => {
            return {
              ...prevFiles,
              [key]: undefined,
            };
          });
        }}
        onUploadError={(error, { key }) => {
          setFiles((prevFiles) => {
            return {
              ...prevFiles,
              [key]: {
                status: 'error',
              },
            };
          });
        }}
        onUploadSuccess={({ key }) => {
          setFiles((prevFiles) => {
            return {
              ...prevFiles,
              [key]: {
                status: 'success',
              },
            };
          });
        }}
        onUploadStart={({ key }) => {
          setFiles((prevFiles) => {
            return {
              ...prevFiles,
              [key]: {
                status: 'uploading',
              },
            };
          });
        }}
      />
      {Object.keys(files).map((key) => {
        return files[key] ? (
          <div>
            {key}: {files[key].status}
          </div>
        ) : null;
      })}
    </>
  );
};

path Usage

The path prop of the FileUploader is prepended to the key value (resolved from either the file itself or the returned key of processFile) submitted to S3. Using a '/' as the last character of path allows uploading to a specific folder inside the provided accessLevel folder.

import { FileUploader } from '@aws-amplify/ui-react-storage';

export const App = () => {
  return (
    <FileUploader
      path="public/images/"
      acceptedFileTypes={['image/*']}
      maxFileCount={1}
    />
  );
};

Adding metadata

Metadata is added as an object with string key-value pairs. It is sent as custom HTTP headers with the name x-amz-meta-[key]. For example, if your metadata for a file was {mode: 'night'}, it would set the x-amz-meta-mode HTTP header to night.

You can add metadata by adding a metadata object in the return object of processFile.

Drop files here or

import { FileUploader } from '@aws-amplify/ui-react-storage';

const processFile = ({ file, key }) => {
  return {
    file,
    key,
    metadata: {
      id: key,
    },
  };
};

export function App() {
  return (
    <FileUploader
      acceptedFileTypes={['image/*']}
      path="public/"
      maxFileCount={3}
      showThumbnails={true}
      processFile={processFile}
    />
  );
}

Accelerate Endpoint

Amazon S3 transfer acceleration optimizes transfer speeds from around the world into S3 buckets. When you use Transfer Acceleration, additional data transfer charges might apply. For more information about pricing, see Amazon S3 pricing.

To use transfer acceleration you first need to enable it on your S3 bucket. Then add useAccelerateEndpoint on the <FileUploader /> component. By default transfer acceleration is off.

<FileUploader
  acceptedFileTypes={['image/*']}
  maxFileCount={10}
  useAccelerateEndpoint
/>

You can also choose whether or not to use transfer acceleration at the file level by returning useAccelerateEndpoint from the processFile function.

<FileUploader
  acceptedFileTypes={['image/*']}
  maxFileCount={10}
  processFile={({ file, key }) => {
    return {
      file,
      key,
      useAccelerateEndpoint: file.size > 10000 ? true : false,
    };
  }}
/>

Customization

Text and labels

All text in the FileUploader component is customizable with the displayText prop.

drag-and-drop here

import { FileUploader } from '@aws-amplify/ui-react-storage';

export const App = () => {
  return (
    <FileUploader
      acceptedFileTypes={['image/*']}
      path="public/"
      maxFileCount={1}
      displayText={{
        // some text are plain strings
        dropFilesText: 'drag-and-drop here',
        browseFilesText: 'Open file picker',
        // others are functions that take an argument
        getFilesUploadedText(count) {
          return `${count} images uploaded`;
        },
      }}
    />
  );
};

Display text props

NameDescriptionType
getFilesUploadedText?
(count: number) => string
getFileSizeErrorText?
(sizeText: string) => string
getRemainingFilesText?
(count: number) => string
getUploadingText?
(percentage: number) => string
getUploadButtonText?
(count: number) => string
getMaxFilesErrorText?
(count: number) => string
getErrorText?
(message: string) => string
getPausedText?
(percentage: string) => string
doneButtonText?Default: "Done"
string
clearAllButtonText?Default: "Clear all"
string
extensionNotAllowedText?Default: "Extension not allowed"
string
browseFilesText?Default: "Browse files"
string
dropFilesText?Default: "Drop files here or"
string
pauseButtonText?Default: "Pause"
string
resumeButtonText?Default: "Resume"
string
uploadSuccessfulText?Default: "Uploaded successfully"
string

Internationalization

You can use the displayText prop to also support different languages. Use an open source library like i18next, react-intl, or make your own:

Drop files here or

import * as React from 'react';
import { ToggleButtonGroup, ToggleButton } from '@aws-amplify/ui-react';
import { FileUploader } from '@aws-amplify/ui-react-storage';

const dictionary = {
  // use default strings for english
  en: null,
  es: {
    getFilesUploadedText(count) {
      return `${count} ${
        count === 1 ? 'archivo cargado' : 'archivos cargados'
      }`;
    },
    getFileSizeErrorText(sizeText) {
      return `El tamaño del archivo debe ser menor a ${sizeText}`;
    },
    getRemainingFilesText(count) {
      return `${count} ${count === 1 ? 'archivo' : 'archivos'} subiendo`;
    },
    getUploadingText(percentage) {
      return `Subiendo${percentage > 0 ? `: ${percentage}%` : ''}`;
    },
    getUploadButtonText(count) {
      return `Cargar ${count} ${count === 1 ? 'archivo' : 'archivos'}`;
    },
    getMaxFilesErrorText(count) {
      return `No se pueden seleccionar más de ${count} ${
        count === 1 ? 'archivo' : 'archivos'
      }. Elimine archivos antes de actualizar.`;
    },
    getErrorText(message) {
      return message;
    },
    doneButtonText: 'Listo',
    clearAllButtonText: 'Limpiar todo',
    extensionNotAllowedText: 'Extensión no permitida',
    browseFilesText: 'Buscar archivos',
    dropFilesText: 'Arrastre los archivos aquí o',
    pauseButtonText: 'Pausa',
    resumeButtonText: 'Reanudar',
    uploadSuccessfulText: 'Carga exitosa',
    getPausedText(percentage) {
      return `Pausado: ${percentage}%`;
    },
  },
};

export const App = () => {
  const [language, setLanguage] = React.useState('en');
  return (
    <>
      <ToggleButtonGroup
        value={language}
        isExclusive
        onChange={(value) => setLanguage(value)}
      >
        <ToggleButton value="en">En</ToggleButton>
        <ToggleButton value="es">Es</ToggleButton>
      </ToggleButtonGroup>
      <FileUploader
        acceptedFileTypes={['image/*']}
        path="public/"
        maxFileCount={1}
        displayText={dictionary[language]}
      />
    </>
  );
};

Component overrides

Don't like how things look? Use your own components inside the FileUploader! You can pass your own components with the components prop. The available components to override are: Container, FileList, FileListHeader, FileListFooter, DropZone, and FilePicker.

You can even use a completely different UI kit like MUI, Chakra, or your own design system!

Drop files here


import * as React from 'react';
import {
  Card,
  Button,
  Flex,
  Text,
  Divider,
  Image,
  Loader,
  Icon,
} from '@aws-amplify/ui-react';
import { FileUploader } from '@aws-amplify/ui-react-storage';

export const App = () => {
  return (
    <FileUploader
      acceptedFileTypes={['image/*']}
      path="public/"
      maxFileCount={100}
      components={{
        Container({ children }) {
          return <Card variation="elevated">{children}</Card>;
        },
        DropZone({ children, displayText, inDropZone, ...rest }) {
          return (
            <Flex
              alignItems="center"
              direction="column"
              padding="medium"
              backgroundColor={inDropZone ? 'primary.10' : ''}
              {...rest}
            >
              <Text>Drop files here</Text>
              <Divider size="small" label="or" maxWidth="10rem" />
              {children}
            </Flex>
          );
        },
        FilePicker({ onClick }) {
          return (
            <Button variation="primary" onClick={onClick}>
              Browse Files
            </Button>
          );
        },
        FileList({ files, onCancelUpload, onDeleteUpload }) {
          return (
            <Flex direction="row">
              {files.map(({ file, key, progress, id, status, uploadTask }) => (
                <Flex
                  key={key}
                  justifyContent="center"
                  alignItems="center"
                  width="5rem"
                  height="5rem"
                  position="relative"
                >
                  <Image
                    borderRadius="small"
                    height="100%"
                    objectFit="cover"
                    src={URL.createObjectURL(file)}
                    alt={key}
                  />
                  {progress < 100 ? (
                    <Loader
                      position="absolute"
                      size="large"
                      percentage={progress}
                      isDeterminate
                      isPercentageTextHidden
                    />
                  ) : null}

                  <Button
                    opacity="50"
                    borderRadius="xxl"
                    backgroundColor="background.primary"
                    position="absolute"
                    variation="link"
                    size="small"
                    onClick={() => {
                      if (status === 'uploading') {
                        onCancelUpload({ id, uploadTask });
                      } else {
                        onDeleteUpload({ id });
                      }
                    }}
                  >
                    <Icon
                      fontSize="large"
                      color="font.error"
                      viewBox={{ width: 512, height: 512 }}
                      paths={[
                        {
                          d: 'M448 256c0-106-86-192-192-192S64 150 64 256s86 192 192 192 192-86 192-192z',
                          strokeWidth: '32',
                          fill: 'none',
                          strokeMiterlimit: '10',
                          stroke: 'currentColor',
                        },
                        {
                          d: 'M320 320L192 192m0 128l128-128',
                          strokeWidth: '32',
                          fill: 'none',
                          strokeLinecap: 'round',
                          stroke: 'currentColor',
                        },
                      ]}
                    />
                  </Button>
                </Flex>
              ))}
            </Flex>
          );
        },
      }}
    />
  );
};

FilePicker props

NameDescriptionType
children
React.ReactNode
onClick
React.MouseEventHandler<HTMLButtonElement>

DropZone props

NameDescriptionType
acceptedFileTypesList of accepted file types
string[]
children
React.ReactNode
displayTextTest strings that are used in the component
FileUploaderDisplayText
isLoading?
boolean
onDragStart
(event: React.DragEvent<HTMLDivElement>) => void
onDragEnter
(event: React.DragEvent<HTMLDivElement>) => void
onDragLeave
(event: React.DragEvent<HTMLDivElement>) => void
onDragOver
(event: React.DragEvent<HTMLDivElement>) => void
onDrop
(event: React.DragEvent<HTMLDivElement>) => void
inDropZone
boolean

Imperative handles

The files state is managed within the FileUploader component itself. To allow for clearing the internal files state, FileUploader exposes a custom ref handle to the parent component with a clearFiles method.

Drop files here or

import * as React from 'react';
import { Button } from '@aws-amplify/ui-react';
import { FileUploader } from '@aws-amplify/ui-react-storage';

export const App = () => {
  const ref = React.useRef(null);

  return (
    <>
      <FileUploader
        acceptedFileTypes={['image/*']}
        path="public/"
        maxFileCount={3}
        ref={ref}
      />
      <Button onClick={() => ref.current.clearFiles()}>Clear Files</Button>
    </>
  );
};

Theming

Drop files here or

import { ThemeProvider } from '@aws-amplify/ui-react';
import { FileUploader } from '@aws-amplify/ui-react-storage';

const theme = {
  name: 'my-theme',
  tokens: {
    borderWidths: {
      small: '2px',
    },
    components: {
      fileuploader: {
        dropzone: {
          borderColor: '{colors.primary.60}',
        },
      },
    },
  },
};

export const App = () => {
  return (
    <ThemeProvider theme={theme}>
      <FileUploader
        acceptedFileTypes={['image/*']}
        path="public/"
        maxFileCount={5}
      />
    </ThemeProvider>
  );
};

Target Classes

If you like, you can target classes directly or use CSS variables to make changes to the look and feel of the File Uploader.

ClassDescription
amplify-fileuploader
amplify-fileuploader__dropzone
amplify-fileuploader__dropzone__icon
amplify-fileuploader__dropzone__text
amplify-fileuploader__file__picker
amplify-fileuploader__file
amplify-fileuploader__file__wrapper
amplify-fileuploader__file__list
amplify-fileuploader__file__name
amplify-fileuploader__loader
amplify-fileuploader__file__size
amplify-fileuploader__file__info
amplify-fileuploader__file__image
amplify-fileuploader__file__main
amplify-fileuploader__file__status
amplify-fileuploader__previewer
amplify-fileuploader__previewer__text
amplify-fileuploader__previewer__actions
amplify-fileuploader__previewer__footer
  • --amplify-components-fileuploader-dropzone-active-background-color
  • --amplify-components-fileuploader-dropzone-active-border-color
  • --amplify-components-fileuploader-dropzone-active-border-radius
  • --amplify-components-fileuploader-dropzone-active-border-style
  • --amplify-components-fileuploader-dropzone-active-border-width
  • --amplify-components-fileuploader-dropzone-background-color
  • --amplify-components-fileuploader-dropzone-border-color
  • --amplify-components-fileuploader-dropzone-border-radius
  • --amplify-components-fileuploader-dropzone-border-style
  • --amplify-components-fileuploader-dropzone-border-width
  • --amplify-components-fileuploader-dropzone-gap
  • --amplify-components-fileuploader-dropzone-icon-color
  • --amplify-components-fileuploader-dropzone-icon-font-size
  • --amplify-components-fileuploader-dropzone-padding-block
  • --amplify-components-fileuploader-dropzone-padding-inline
  • --amplify-components-fileuploader-dropzone-text-align
  • --amplify-components-fileuploader-dropzone-text-color
  • --amplify-components-fileuploader-dropzone-text-font-size
  • --amplify-components-fileuploader-dropzone-text-font-weight
  • --amplify-components-fileuploader-file-align-items
  • --amplify-components-fileuploader-file-background-color
  • --amplify-components-fileuploader-file-border-color
  • --amplify-components-fileuploader-file-border-radius
  • --amplify-components-fileuploader-file-border-style
  • --amplify-components-fileuploader-file-border-width
  • --amplify-components-fileuploader-file-gap
  • --amplify-components-fileuploader-file-image-background-color
  • --amplify-components-fileuploader-file-image-border-radius
  • --amplify-components-fileuploader-file-image-color
  • --amplify-components-fileuploader-file-image-height
  • --amplify-components-fileuploader-file-image-width
  • --amplify-components-fileuploader-file-name-color
  • --amplify-components-fileuploader-file-name-font-size
  • --amplify-components-fileuploader-file-name-font-weight
  • --amplify-components-fileuploader-file-padding-block
  • --amplify-components-fileuploader-file-padding-inline
  • --amplify-components-fileuploader-file-size-color
  • --amplify-components-fileuploader-file-size-font-size
  • --amplify-components-fileuploader-file-size-font-weight
  • --amplify-components-fileuploader-filelist-flex-direction
  • --amplify-components-fileuploader-filelist-gap
  • --amplify-components-fileuploader-loader-stroke-empty
  • --amplify-components-fileuploader-loader-stroke-filled
  • --amplify-components-fileuploader-loader-stroke-linecap
  • --amplify-components-fileuploader-loader-stroke-width
  • --amplify-components-fileuploader-previewer-background-color
  • --amplify-components-fileuploader-previewer-body-gap
  • --amplify-components-fileuploader-previewer-body-padding-block
  • --amplify-components-fileuploader-previewer-body-padding-inline
  • --amplify-components-fileuploader-previewer-border-color
  • --amplify-components-fileuploader-previewer-border-radius
  • --amplify-components-fileuploader-previewer-border-style
  • --amplify-components-fileuploader-previewer-border-width
  • --amplify-components-fileuploader-previewer-footer-justify-content
  • --amplify-components-fileuploader-previewer-max-height
  • --amplify-components-fileuploader-previewer-max-width
  • --amplify-components-fileuploader-previewer-padding-block
  • --amplify-components-fileuploader-previewer-padding-inline
  • --amplify-components-fileuploader-previewer-text-color
  • --amplify-components-fileuploader-previewer-text-font-size
  • --amplify-components-fileuploader-previewer-text-font-weight

Amplify open source software, documentation and community are supported by Amazon Web Services.

© 2024 Amazon Web Services, Inc. and its affiliates. All rights reserved. View the site terms and privacy policy.

Flutter and the related logo are trademarks of Google LLC. We are not endorsed by or affiliated with Google LLC.