This article will explain how you can build a file previewer in React that works for images and videos. With this article's help, you can create your own and make support for other files.
This article only showcases the preview for an image and video.
Demo
Creating FilePreviewer
Component
First, let's just create a file components/FilePreviewer.js
after that we need to import two things in that file useState
and useRef
.
// components/FilePreviewer.js
import { useState, useRef } from "react";
Create a FilePreviewer
function and export it as default.
// components/FilePreviewer.js
// ....
export default function FilePreviewer() {}
Now we render the UI for FIle Picker and in that there will be two buttons. One for selecting files and the other for clearing file input. Let's see how it's going to look like.
// components/FilePreviewer.js
import { useState, useRef } from "react";
export default function FilePreviewer() {
return (
<div>
<h1>Preview Image/Video</h1>
<div className="btn-container">
<input type="file" accept="image/*, video/*" hidden />
<button className="btn">Choose</button>
<button className="btn">x</button>
</div>
<div className="preview">
<img src="" alt="" />
<video controls src=""></video>
</div>
</div>
);
}
This is just a starter code, I am going to add more things to this. First, understand what is going on. As you can see inside the btn-container
class there are three inputs. One for selecting files but I won't use standard file input because when the user selects the file by standard input it shows the name of the file which I don't want (as shown in the following screenshot).
Handling File Input button
I have created a new button to choose the file. To make this work we need to create a reference (ref) for file input. and handle the onChange
event after that it will look something like this.
// components/FilePreviewer.js
import { useState, useRef } from "react";
export default function FilePreviewer() {
return (
// inside .btn-container
<input ref={filePicekerRef} accept="image/*, video/*" onChange={previewFile} type="file" hidden />
// ...
);
}
We will create the previewFile
function in just a moment to handle the file selection.
Creating Custom File input Button
Now as I have hidden the original file input button we need to create our own.
// components/FilePreviewer.js
import { useState, useRef } from "react";
export default function FilePreviewer() {
return (
// inside .btn-container
<button className="btn" onClick={()=> filePicekerRef.current.click()} >
Choose
</button>
// ...
);
}
In this, I am just triggering the file input button through ref
when the user clicks this button.
File Selection
As we are handling two files (image and video). we need to create two states for that imagePreview
and videoPreview
.
// components/FilePreviewer.js
import { useState, useRef } from "react";
export default function FilePreviewer() {
const [imagePreview, setImagePreview] = useState(null);
const [videoPreview, setVideoPreview] = useState(null);
return (
// ...
);
}
Now its' time to create a filePreview
function.
// components/FilePreviewer.js
export default function FilePreviewer() {
// ...
function previewFile(e) {
// Reading New File (open file Picker Box)
const reader = new FileReader();
// Gettting Selected File (user can select multiple but we are choosing only one)
const selectedFile = e.target.files[0];
if (selectedFile) {
reader.readAsDataURL(selectedFile);
}
// As the File loaded then set the stage as per the file type
reader.onload = (readerEvent) => {
if (selectedFile.type.includes("image")) {
setImagePreview(readerEvent.target.result);
} else if (selectedFile.type.includes("video")) {
setVideoPreview(readerEvent.target.result);
}
};
}
// ...
}
I know it's too much so let's break it down. I am using FileReader to handle the file selection.
- I have created an instance called
reader
. - Then we are getting the
selectedFile
from an input field (I am targeting only one file, the user can select multiple files but I am handling only one file). - If the user has selected a file then read that as Data URLs.
- When the file is loaded then check for the file type and set the image and video accordingly.
Preview the file
After file selection is done then we need to preview the file to the user. For that I have already created a container called .preview
, In that, there were two elements img
and video
. Now we need to render these elements conditionally. and after that they will look like this-
// components/FilePreviewer.js
<div className="preview">
{imagePreview != null && <img src={imagePreview} alt="" />}
{videoPreview != null && <video controls src={videoPreview}></video>}
</div>
Clear Input Field
Now, what if the user wants to clear the input field or remove the image he has selected. We haven't implemented that yet. To do that I've created a close
button earlier. Now let's just add the functionality to it. When the user clicks on the button then it should fire clearFiles
function. So let's just create it.
// components/FilePreviewer.js
function clearFiles() {
setImagePreview(null);
setVideoPreview(null);
}
That's all we need to create a working file Previewer. It can preview an image and a video.
Full Code of FilePreviewer.js
// components/FilePreviewer.js
import { useState, useRef } from "react";
export default function FilePreviewer() {
// FIles States
const [imagePreview, setImagePreview] = useState(null);
const [videoPreview, setVideoPreview] = useState(null);
// FIle Picker Ref because we are not useing the standard File picker input
const filePicekerRef = useRef(null);
function previewFile(e) {
// Reading New File (open file Picker Box)
const reader = new FileReader();
// Gettting Selected File (user can select multiple but we are choosing only one)
const selectedFile = e.target.files[0];
if (selectedFile) {
reader.readAsDataURL(selectedFile);
}
// As the File loaded then set the stage as per the file type
reader.onload = (readerEvent) => {
if (selectedFile.type.includes("image")) {
setImagePreview(readerEvent.target.result);
} else if (selectedFile.type.includes("video")) {
setVideoPreview(readerEvent.target.result);
}
};
}
function clearFiles() {
setImagePreview(null);
setVideoPreview(null);
}
return (
<div>
<h1>Preview Image/Video</h1>
<div className="btn-container">
<input
ref={filePicekerRef}
accept="image/*, video/*"
onChange={previewFile}
type="file"
hidden
/>
<button className="btn" onClick={() => filePicekerRef.current.click()}>
Choose
</button>
{(imagePreview || videoPreview) && (
<button className="btn" onClick={clearFiles}>
x
</button>
)}
</div>
<div className="preview">
{imagePreview != null && <img src={imagePreview} alt="" />}
{videoPreview != null && <video controls src={videoPreview}></video>}
</div>
</div>
);
}
Now we just need to import this container in App.js
and render it. App.js
will look something like this.
// src/App.js
import "./styles.css";
import FilePreviewer from "./components/FilePreviewer";
export default function App() {
return (
<div className="App">
<FilePreviewer />
</div>
);
}
You can find the full code in the following Sandbox
It takes a little white to render the video if the size of the video is large. You can setup a loading state for that.
What's Next?
Now after that you can take this further and add support for other files such as text, pdf, and others. You can also add support for multiple files and there are many things you can do.
Top comments (3)
It's easy to understand :) thanks for the good post
Thanks for the appreciation โจ
Good post.