How to Use File Upload in React with MUI 5

In this tutorial, we’ll walk you through the process of implementing file uploads in a React application using Material-UI (v5). We’ll explore Material-UI 5’s file upload button and utilize the useState hook to showcase an image upload example in React.

Install & Setup Vite + React + Typescript + MUI 5

React Material UI 5 File Upload Example

1. React Material-UI 5 File Upload with a Button.

import * as React from "react";
import Button from "@mui/material/Button";
import Stack from "@mui/material/Stack";

export default function FileUpload() {
  return (
    <Stack direction="row" alignItems="center" spacing={2}>
      <Button variant="contained" component="label">
        Upload
        <input hidden accept="image/*" multiple type="file" />
      </Button>
    </Stack>
  );
}
mui 5 file upload with button

Before you start working with icons, make sure to install the @mui/icons-material package.

# with npm
npm install @mui/icons-material

# with yarn
yarn add @mui/icons-material

Build a Drag & Drop Image File Upload with React and Material UI

2. Adding Icons to React Material-UI 5 File Upload.

import * as React from "react";
import IconButton from "@mui/material/IconButton";
import PhotoCamera from "@mui/icons-material/PhotoCamera";
import Stack from "@mui/material/Stack";
import { Container } from "@mui/material";

export default function FileUpload() {
  return (
    <Container maxWidth="md" sx={{ mt: 8 }}>
      <Stack direction="row" alignItems="center" spacing={2}>
        <IconButton
          color="primary"
          aria-label="upload picture"
          component="label"
        >
          <input hidden accept="image/*" type="file" />
          <PhotoCamera />
        </IconButton>
      </Stack>
    </Container>
  );
}
 file upload with icon

3. Uploading and Displaying Image Files in React Material-UI 5 Using the useState Hook.

import { useState } from "react";
import Button from "@mui/material/Button";
import Stack from "@mui/material/Stack";
import { Container } from "@mui/material";

export default function UploadButtons() {
  const [imageUrl, setImageUrl] = useState(null);

  const handleFileUpload = (event) => {
    const file = event.target.files[0];
    const reader = new FileReader();

    reader.onloadend = () => {
      setImageUrl(reader.result);
    };

    reader.readAsDataURL(file);
  };

  return (
    <Container maxWidth="md" sx={{ mt: 8 }}>
      <Stack direction="row" alignItems="center" spacing={2}>
        <label htmlFor="upload-image">
          <Button variant="contained" component="span">
            Upload
          </Button>
          <input
            id="upload-image"
            hidden
            accept="image/*"
            type="file"
            onChange={handleFileUpload}
          />
        </label>
        {imageUrl && <img src={imageUrl} alt="Uploaded Image" height="300" />}
      </Stack>
    </Container>
  );
}
image show upload file react mui 5

4. Building a Multiple File Upload Component in React with Material UI 5.

import { useState } from 'react';
import { Button, Typography, Box } from '@mui/material';

const MultipleFileUpload = () => {
  const [selectedFiles, setSelectedFiles] = useState([]);

  const handleFileChange = (event) => {
    const files = Array.from(event.target.files);
    setSelectedFiles(files);
  };

  const handleUpload = () => {
    if (selectedFiles.length > 0) {
      const formData = new FormData();
      selectedFiles.forEach((file, index) => {
        formData.append(`file${index + 1}`, file);
      });
      console.log('Uploading files...', formData);
    } else {
      console.error('No files selected');
    }
  };

  return (
    <Box p={3} border="1px dashed #ccc" borderRadius={8} textAlign="center">
      <input
        type="file"
        accept="image/*"
        multiple
        onChange={handleFileChange}
        style={{ display: 'none' }}
        id="multiple-file-input"
      />
      <label htmlFor="multiple-file-input">
        <Button variant="outlined" component="span">
          Select Files
        </Button>
      </label>
      {selectedFiles.length > 0 && (
        <div>
          <Typography variant="subtitle1" mt={2}>
            Selected Files:
          </Typography>
          <ul>
            {selectedFiles.map((file) => (
              <li key={file.name}>{file.name}</li>
            ))}
          </ul>
          <Button variant="contained" color="primary" onClick={handleUpload} mt={2}>
            Upload
          </Button>
        </div>
      )}
    </Box>
  );
};

export default MultipleFileUpload;
 multiple file upload

5. React Material UI 5 image file upload with validation.

import { useState } from "react";
import { Button, Typography, Box } from "@mui/material";

const MAX_FILE_SIZE_MB = 5;
const ALLOWED_FILE_TYPES = ["image/jpeg", "image/png", "image/gif"];

const ImageFileUpload = () => {
  const [selectedFile, setSelectedFile] = useState(null);
  const [error, setError] = useState(null);

  const handleFileChange = (event) => {
    const file = event.target.files[0];

    // File type validation
    if (!ALLOWED_FILE_TYPES.includes(file.type)) {
      setError("Invalid file type. Please upload a JPEG, PNG, or GIF image.");
      return;
    }

    // File size validation
    if (file.size > MAX_FILE_SIZE_MB * 1024 * 1024) {
      setError(
        `File size exceeds ${MAX_FILE_SIZE_MB} MB. Please choose a smaller file.`
      );
      return;
    }

    setSelectedFile(file);
    setError(null);
  };

  const handleUpload = () => {
    if (selectedFile) {
      const formData = new FormData();
      formData.append("file", selectedFile);

      console.log("Uploading file...", formData);
    } else {
      console.error("No file selected");
    }
  };

  return (
    <Box p={3} border="1px dashed #ccc" borderRadius={8} textAlign="center">
      <input
        type="file"
        accept="image/*"
        onChange={handleFileChange}
        style={{ display: "none" }}
        id="image-file-input"
      />
      <label htmlFor="image-file-input">
        <Button variant="outlined" component="span">
          Select Image
        </Button>
      </label>
      {selectedFile && (
        <div>
          <Typography variant="subtitle1" mt={2}>
            Selected Image: {selectedFile.name}
          </Typography>
          <Button
            variant="contained"
            color="primary"
            onClick={handleUpload}
            mt={2}
          >
            Upload
          </Button>
        </div>
      )}
      {error && (
        <Typography variant="body2" color="error" mt={2}>
          {error}
        </Typography>
      )}
    </Box>
  );
};

export default ImageFileUpload;
 image file upload with validation
Aaronn
Aaronn

Hey there! I'm Aaronn, a Full Stack Developer who's all about React, NEXTJS, Node.js, and Tailwind CSS. I'm on a mission to craft awesome websites that look great and work even better.