An open API service indexing awesome lists of open source software.

https://github.com/jacksonkasi0/nextjs-multi-image-upload


https://github.com/jacksonkasi0/nextjs-multi-image-upload

Last synced: 2 months ago
JSON representation

Awesome Lists containing this project

README

        

# Next.js Multi-Image Upload

A reusable, responsive multi-image upload component built with Next.js, TypeScript, Tailwind CSS, `shadcn/ui`, and `react-hook-form`. This project provides a simple, type-safe solution for uploading multiple images with progress tracking, deletion feedback, and form validation integration.

![Demo - Next.js Multi-Image Upload](/public/og-image.png)

## Features

- **Multi-Image Upload**: Upload multiple files with a configurable maximum limit (default: 5).
- **Responsive Design**: Flex-based layout that adapts to different screen sizes using Tailwind CSS.
- **Progress Tracking**: Displays upload progress as a percentage overlay on each image.
- **Deletion Feedback**: Glow-and-dim animation during image deletion to indicate the action is in progress.
- **Form Integration**: Fully compatible with `react-hook-form` for controlled form validation and error handling.
- **Type-Safe**: Written in TypeScript with proper type definitions for props and internal state.
- **Customizable**: Easily styled via Tailwind CSS classes and extensible through props.
- **API Support**: Integrates with signed URL generation and file upload/deletion APIs (server-side logic included).

## Demo

-



Next.js Multi-Image Upload






## Prerequisites

- Node.js (v18+ recommended)
- Bun (or npm/yarn/pnpm) as the package manager
- Next.js project with TypeScript configured
- Tailwind CSS installed
- `shadcn/ui` components (`button`, `form`, `label`) installed
- `react-hook-form` and `@hookform/resolvers/zod` for form validation
- `zod` for schema validation
- `lucide-react` for icons

## Installation

1. **Clone the Repository** (optional, if not copying files directly):

```bash
git clone https://github.com/jacksonkasi0/nextjs-multi-image-upload.git
cd nextjs-multi-image-upload
```

2. **Install Dependencies**:

```bash
bun install
```

3. **Set Up Environment Variables**:

- Copy `example.env` to `.env` and configure your API keys or endpoints (e.g., for signed URL generation).
- Example `.env`:

```bash
NODE_ENV="production"

# S3
AWS_ACCESS_KEY_ID="xxxxx" # your access key
AWS_SECRET_ACCESS_KEY="xxxxxxx" # your secret key
AWS_REGION="xxxxxx" # example: ap-south-1, us-east-1
AWS_BUCKET_NAME="xxxxx" # your bucket name
```

πŸ‘€ **Check the [`Secure_S3_Bucket_Setup.md`](./Secure_S3_Bucket_Setup.md) guide for setting up a secure S3 bucket.** πŸ›‘οΈ

4. **Run the Development Server**:

```bash
bun dev
```

Open [http://localhost:3000](http://localhost:3000) to see the app.

## Usage

### Integrating into Your Project

To use the `MultiImageUpload` component in your own Next.js project, follow these steps:

#### 1. Copy Required Files

Copy the following files from this repository into your project:

- **`src/components/multi-image-upload.tsx`**: The core component with upload and deletion logic.
- **`src/api/upload-api.ts`**: Client-side API functions for signed URL generation, uploading, and deletion.
- **`src/app/api/upload/signed-url/route.ts`**: Server-side route to generate signed URLs.
- **`src/app/api/upload/delete/route.ts`**: Server-side route to delete files.
- **`src/components/background.tsx`**: Optional background component for the radial gradient effect.

#### 2. Install Dependencies

Ensure your project has the required dependencies. Add them to your `package.json`:

```bash
bun add react-hook-form @hookform/resolvers/zod zod lucide-react
bun add -D tailwindcss postcss autoprefixer @types/react @types/node typescript
```

If you’re using `shadcn/ui`, initialize it and add the necessary components:

```bash
npx shadcn-ui@latest init
npx shadcn-ui@latest add button form label
```

#### 3. Configure Tailwind CSS

To ensure the `MultiImageUpload` component works correctly with its glow-and-dim animation during deletion, configure your `tailwind.config.ts` with the `shadcn/ui` color variables (e.g., `--muted`, `--primary`) and the custom `glow-effect` animation. Below is an example configuration:

```ts
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ["class"],
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
colors: {
// shadcn/ui color definitions...
},
borderRadius: {
// shadcn/ui radius definitions...
},
animation: {
"glow-effect": "glow-effect 1.5s infinite ease-in-out",
},
keyframes: {
"glow-effect": {
"0%, 100%": {
boxShadow:
"0 0 10px var(--muted-foreground), 0 0 20px var(--muted)",
opacity: "1",
},
"50%": {
boxShadow:
"0 0 20px var(--primary), 0 0 40px var(--primary-foreground)",
opacity: "0.5",
},
},
},
},
},
plugins: [require("tailwindcss-animate")],
};
```

**Important Notes:**

- **Animation**: The `glow-effect` animation is critical for deletion feedback in `MultiImageUpload`. You **must** include the `animation` and `keyframes` definitions as shown above. It uses `box-shadow` and `opacity`, relying on `shadcn/ui` color variables (`--muted`, `--muted-foreground`, `--primary`, `--primary-foreground`).
- **Plugin**: Add the `tailwindcss-animate` plugin to enable custom animations. Install it with:

```bash
bun add -D tailwindcss-animate
```

- **Colors**: Ensure your `shadcn/ui` setup defines the required CSS variables in `globals.css` (e.g., `:root { --muted: 210 40% 96.1%; }`). If not, replace the variables with specific HSL or hex values.

#### 4. Example Usage

Here’s how to use `MultiImageUpload` with `react-hook-form` in a page (e.g., `src/app/page.tsx`):

```tsx
"use client";

import React from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { MultiImageUpload } from "@/components/multi-image-upload";
import Background from "@/components/background";

const schema = z.object({
images: z
.array(z.string().url())
.min(1, "At least 1 image is required")
.max(5, "Maximum 5 images allowed"),
});

type FormData = z.infer;

export default function Page() {
const form = useForm({
resolver: zodResolver(schema),
defaultValues: { images: [] },
});

const onSubmit = (data: FormData) => {
console.log("Submitted:", data.images);
};

return (




(

Images





)}
/>

Submit





);
}
```

#### 5. Set Up API Routes

- Place `signed-url/route.ts` and `delete/route.ts` in your `src/app/api/upload/` directory.
- Update the API logic in `upload-api.ts` to point to your backend (e.g., AWS S3, Cloudinary) if different from the example.

### Props for `MultiImageUpload`

| Prop | Type | Default | Description |
|--------------|------------------------------|-----------------------------------|-----------------------------------------------------------------------------|
| `value` | `string[]` | `[]` | Controlled array of file URLs |
| `onChange` | `(images: string[]) => void` | - | Callback to update the value |
| `maxImages` | `number` | - | Optional maximum number of files allowed |
| `className` | `string` | - | Additional Tailwind CSS classes for styling |
| `name` | `string` | - | Optional field name for React Hook Form integration |
| `imageRegex` | `RegExp` | `/\.(jpeg\|jpg\|png\|gif\|webp\|avif)$/i` | Regex to detect image formats for initial value previews |
| `accept` | `string` | `"image/*"` | MIME types or file extensions accepted by the file input (e.g., `"image/png, image/jpeg"`) |

**Notes:**
- `imageRegex` determines which initial URLs are treated as images for preview rendering. Customize it to support additional formats (e.g., `.svg`).
- `accept` restricts the file picker to specific types during uploads. Use MIME types or extensions (e.g., `"image/*,application/pdf"`).

## File Structure

```
nextjs-multi-image-upload/
β”œβ”€β”€ public/ # Static assets
β”‚ β”œβ”€β”€ file.svg
β”‚ β”œβ”€β”€ globe.svg
β”‚ β”œβ”€β”€ next.svg
β”‚ β”œβ”€β”€ vercel.svg
β”‚ └── window.svg
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ api/
β”‚ β”‚ └── upload-api.ts # Client-side API functions
β”‚ β”œβ”€β”€ app/
β”‚ β”‚ β”œβ”€β”€ api/upload/
β”‚ β”‚ β”‚ β”œβ”€β”€ delete/route.ts # DELETE route for file removal
β”‚ β”‚ β”‚ └── signed-url/route.ts # GET/POST route for signed URLs
β”‚ β”‚ β”œβ”€β”€ favicon.ico
β”‚ β”‚ β”œβ”€β”€ layout.tsx
β”‚ β”‚ └── page.tsx # Example page using MultiImageUpload
β”‚ β”œβ”€β”€ components/
β”‚ β”‚ β”œβ”€β”€ ui/ # shadcn/ui components
β”‚ β”‚ β”‚ β”œβ”€β”€ button.tsx
β”‚ β”‚ β”‚ β”œβ”€β”€ form.tsx
β”‚ β”‚ β”‚ └── label.tsx
β”‚ β”‚ β”œβ”€β”€ background.tsx # Radial gradient background
β”‚ β”‚ └── multi-image-upload.tsx # Main component
β”‚ β”œβ”€β”€ config/
β”‚ β”‚ └── env.ts # Environment variable config
β”‚ β”œβ”€β”€ helpers/
β”‚ β”‚ └── upload.ts # Upload-related utilities
β”‚ β”œβ”€β”€ lib/
β”‚ β”‚ └── utils.ts # Utility functions (e.g., cn)
β”‚ └── styles/
β”‚ └── globals.css # Global styles
β”œβ”€β”€ .env # Environment variables
β”œβ”€β”€ .gitignore
β”œβ”€β”€ README.md
β”œβ”€β”€ bun.lock # Bun lockfile
β”œβ”€β”€ components.json # shadcn/ui config
β”œβ”€β”€ eslint.config.mjs
β”œβ”€β”€ example.env
β”œβ”€β”€ next-env.d.ts
β”œβ”€β”€ next.config.ts
β”œβ”€β”€ package.json
β”œβ”€β”€ postcss.config.mjs
β”œβ”€β”€ tailwind.config.ts
└── tsconfig.json
```

## Contributing

1. Fork the repository.
2. Create a feature branch (`git checkout -b feature/new-feature`).
3. Commit changes (`git commit -m "Add new feature"`).
4. Push to the branch (`git push origin feature/new-feature`).
5. Open a pull request.

## License

MIT License. See [LICENSE](LICENSE) for details.

## Credits

Created by [jacksonkasi0](https://github.com/jacksonkasi0) & [jacksonkasi1](https://github.com/jacksonkasi1).