Front-End Web & Mobile

Announcing the Amplify UI StorageManager Component

Amplify UI is a collection of accessible, themeable, performant React components that can connect directly to the cloud. Today we are announcing a new cloud-connected UI component called the StorageManager, which lets your users upload and manage files to the cloud. In this post you will learn how to use Amplify’s new StorageManager component to allow users to upload files to Amazon S3 by setting up a new NextJS app and Amplify project with the Storage category.

Video of file dragging and dropping onto the Storage Manager component

If you would like to play around with the StorageManager component without creating any AWS resources, you can fork this StackBlitz project: https://stackblitz.com/edit/amplify-ui-storage-manager It has several configurations of the StorageManager component to play around with. It uses a mocked Amplify Storage backend so files don’t get uploaded anywhere, but you can use it to test the component without spinning up an Amplify project.

Prerequisites

  • You should have the Amplify CLI installed. The easiest way is to install it globally with npm or yarn: npm i -g @aws-amplify/cli
  • An AWS account

Creating a project

First, we are going to create a new NextJS application, but you could use Vite, or any other React framework. If you already have a React application feel free to skip this step.

yarn create next-app example-app
✔ Would you like to use TypeScript with this project? … No / Yes
✔ Would you like to use ESLint with this project? … No / Yes
✔ Would you like to use Tailwind CSS with this project? … No / Yes
✔ Would you like to use `src/` directory with this project? … No / Yes
✔ Would you like to use experimental `app/` directory with this project? … No / Yes
✔ What import alias would you like configured? … @/*

Now go into the project you just created:

cd example-app

Next, we will create a new Amplify project by running the Amplify CLI

amplify init
? Enter a name for the project example-app
The following configuration will be applied:

Project information
| Name: example-app
| Environment: dev
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: react
| Source Directory Path: src
| Distribution Directory Path: build
| Build Command: npm run-script build
| Start Command: npm run-script start

? Initialize the project with the above configuration? Yes

At the end of the project initialization you should see

✅ Initialized your environment successfully.

Your project has been successfully initialized and connected to the cloud!

Now we will add the Storage category:

amplify add storage

Then select “Content” You should see this in your terminal:

? Select from one of the below mentioned services: (Use arrow keys)
❯ Content (Images, audio, video, etc.)
  NoSQL Database
✔ You need to add auth (Amazon Cognito) to your project in order to add storage for user files. Do you want to add auth now? (Y/n) · yes

The Amplify CLI will ask you if you want to add auth to the project as well if you want user-based files. Let’s add it and choose the default configuration. When asked for who should have access, choose “Auth and guest users” and then select “create/update” and “read” for access.

✔ Provide a friendly name for your resource that will be used to label this category in the project: · s3bccbef32

✔ Provide bucket name: · exampleapp1bd08ead8a32499383a72839bae
✔ Who should have access: · Auth and guest users
✔ What kind of access do you want for Authenticated users? · create/update, read, delete
✔ What kind of access do you want for Guest users? · create/update, read, delete
✔ Do you want to add a Lambda Trigger for your S3 Bucket? (y/N) · no

Finally, deploy your Amplify backend:

amplify push

You should see this:


    Current Environment: dev
    
┌──────────┬──────────────────────────────┬───────────┬───────────────────┐
│ Category │ Resource name                │ Operation │ Provider plugin   │
├──────────┼──────────────────────────────┼───────────┼───────────────────┤
│ Auth     │ exampleappc23acc48           │ Create    │ awscloudformation │
├──────────┼──────────────────────────────┼───────────┼───────────────────┤
│ Storage  │ s3b125a798                   │ Create    │ awscloudformation │
└──────────┴──────────────────────────────┴───────────┴───────────────────┘
✔ Are you sure you want to continue? (Y/n) · yes

Select “yes” and sit back while Amplify sets everything up for you (it might take a few minutes). Congrats! Now you have a backend with Storage and Auth capabilities. Now let’s hook up our frontend code to s3 with the StorageManager component.

A quick note about Amplify Storage: When you use the Amplify Storage category it creates a bucket in s3 with 3 folders: public, private, and protected. These correspond to the accessLevel prop in the StorageManager component. When you use the private or protected level, files get uploaded to the bucket with this path <level>/<user id>/<key>. If you choose one of those levels make sure you are using in the StorageManager in your application where a user is logged in via Amplify Auth or you will get an error.
Speaking of Auth, the easiest way to add Auth to your project is with the Amplify Authenticator component!

Install the Amplify UI packages

npm i --save @aws-amplify/ui-react-storage @aws-amplify/ui-react aws-amplify

The StorageManager is the first Amplify UI connected component to go into its own package. We plan to move all connected components to category-based packages (-auth, -storage, -geo, etc.) this year to reduce package sizes so you only install what you need. The @aws-amplify/ui-react-storage package depends on @aws-amplify/ui-react which has all the primitive components and theming.

Configure Amplify

Add these imports to the top of the src/pages/_app.tsx :

import '@aws-amplify/ui-react/styles.css';
import { Amplify } from 'aws-amplify';
import awsconfig from '../aws-exports';

And then after the imports add this to configure Amplify:

Amplify.configure(awsconfig);

Your src/pages/_app.tsx file should look like this now:

import '@aws-amplify/ui-react/styles.css'
import { Amplify } from 'aws-amplify'
import awsconfig from '../aws-exports'
import type { AppProps } from 'next/app'

Amplify.configure(awsconfig);

export default function App({ Component, pageProps }: AppProps) {
  return (
    <Component {...pageProps} />
  )
}

Add the StorageManager component

Now lets add the StorageManager component to our app. At a minimum, you must include the accessLevel, acceptedFileTypes, and maxFileCount props.

  • accessLevel refers to the Amplify Storage access level, which is ‘public’ | ‘private’ | ‘protected’.
  • acceptedFileTypes is an array of HTML file types
  • maxFileCount is how many files you want to allow to be uploaded at a time.

First, import the component:

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

Then replace the JSX of the function with just the StorageManager component:

      <StorageManager
        accessLevel='public'
        acceptedFileTypes={['image/*']}
        maxFileCount={5}
      />

Your src/pages/index.tsx file should look like this now:

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

export default function Home() {
  return (
      <StorageManager
        accessLevel='public'
        acceptedFileTypes={['image/*']}
        maxFileCount={5}
      />
  )
}

Run the development server to see the StorageManager component in action!

npm run dev

Try dragging and dropping files onto the StorageManager or opening up the file picker and see files get uploaded. Here you can see me upload a picture of my two cats:Video of file dragging and dropping onto the Storage Manager component

To verify the files are being uploaded properly, let’s open up Amplify Studio. First, open up the Amplify console from the CLI by running:

amplify console

Then selecting AWS console . Your browser should open and direct you to your Amplify project. Then click on the ‘Set up Amplify Studio’ button.

Screenshot of the Amplify console and how to enable Amplify Studio

Once Studio is set up, go back to your Amplify app using the breadcrumbs or the navigation panel on the left. Then click ‘Launch Studio’ which will open a new browser tab.

Screenshot of how to access Amplify Studio

In Amplify Studio, navigate to the ‘File Browser’ tab. Then click on the ‘public’ folder, and you should see any files uploaded there:

Screenshot of Amplify Studio's file browser

Congrats! You now have a NextJS app where users can upload files with Amplify.

(Optional) Customizing the StorageManager

You can stop here, or take a look at some of the cool features of the StorageManager component.

Pre-upload processing

You might want to modify the file(s) and/or file name(s) before they are uploaded. The most common use for this is to ensure unique s3 keys so files aren’t overridden. The StorageManager uploads files to s3 with the filename as the key in s3 by default, but you can override that behavior by modifying the key before upload. Let’s add a processFile function in src/pages/index.tsx that will add a timestamp to the filename:

const processFile = ({ file, key }) => {
  const fileParts = key.split('.');
  const ext = fileParts.pop();
  return {
    file,
    // This will prepend a unix timestamp
    // to ensure all files uploaded are unique
    key: `${Date.now()}${fileParts.join('.')}.${ext}`,
  };
}

Now add processFile to a prop on the StorageManager:

    <StorageManager
      accessLevel='public'
      acceptedFileTypes={['image/*']}
      maxFileCount={5}
      processFile={processFile}
      onUploadSuccess={({ key }) => {
        // This will return the key of the file uploaded
        console.log(key);
      }}
    />

Now all files uploaded will have a hash for the filename so you can ensure all files are unique. Other common uses for this would be if you want to optimize files before upload by stripping metadata, or adding custom validation like ensuring a file is valid JSON before uploading.

Component overrides

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

Let’s change the FilePicker button to be a primary button so it stands out more. First import the Button component from @aws-amplify/ui-react :

import { Button } from '@aws-amplify/ui-react'

Then add a components prop that overrides the FilePicker component by adding this right before the closing of the StorageManger JSX tag:

      components={{
        FilePicker({ onClick }) {
          return (
            <Button variation="primary" onClick={onClick}>
              Browse Files
            </Button>
          );
        },
      }}

You can even use a completely different UI kit like MUI, Chakra, or your own design system! In the StackBlitz project you can see a StorageManager component built with Chakra: https://stackblitz.com/edit/amplify-ui-storage-manager?file=src%2FWithChakra.tsx

Theming

The StorageManager component uses the Amplify UI theming system and Amplify UI primitive components like Button. If you are already using an Amplify UI theme, this component will just work. If plain CSS is more your speed, you can customize how the StorageManager component looks with CSS classes and custom properties. To learn more about theming, check out the theming docs.

Summary and next steps

In this post we created a NextJS app and added file uploading capabilities with the Amplify UI StorageManager component. To clean up your project, run amplify delete from the command line or delete the app from the AWS console.

Head over the Amplify UI docs to see all the ways you can customize the StorageManager component: https://ui.docs.amplify.aws/react/connected-components/storage/storagemanager.