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>
);
}
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>
);
}
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>
);
}
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;
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;