Preview File before uploading in React

Jun 3, 2022
7 min read
1392 words

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.

Warning

This article only showcases the preview for an image and video.

Demo

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

import { useState, useRef } from "react";
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).

filename shows

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() {
 
  // FIle Picker Ref because we are not useing the standard File picker input
	const filePicekerRef = useRef(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">Choose</button>
        <button className="btn">x</button>
      </div>
      <div className="preview">
        <img src="" alt="" />
        <video controls src=""></video>
      </div>
    </div>
  );
}

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() {
  const filePicekerRef = useRef(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>
        <button className="btn">x</button>
      </div>
      <div className="preview">
        <img src="" alt="" />
        <video controls src=""></video>
      </div>
    </div>
  );
}

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);
  const filePicekerRef = useRef(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>
        <button className="btn">x</button>
      </div>
      <div className="preview">
        <img src="" alt="" />
        <video controls src=""></video>
      </div>
    </div>
  );
}

Now its' time to create a filePreview function.

components/FilePreviewer.js

import { useState, useRef } from "react";
export default function FilePreviewer() {
  const [imagePreview, setImagePreview] = useState(null);
  const [videoPreview, setVideoPreview] = useState(null);
  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);
      }
    };
  }
  
  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>
        <button className="btn">x</button>
      </div>
      <div className="preview">
        <img src="" alt="" />
        <video controls src=""></video>
      </div>
    </div>
  );
}

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

import { useState, useRef } from "react";
export default function FilePreviewer() {
  const [imagePreview, setImagePreview] = useState(null);
  const [videoPreview, setVideoPreview] = useState(null);
  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);
      }
    };
  }
  
  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>
        <button className="btn">x</button>
      </div>
      <div className="preview">
        {imagePreview != null && <img src={imagePreview} alt="" />}
        {videoPreview != null && <video controls src={videoPreview}></video>}
      </div>
    </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

import { useState, useRef } from "react";
export default function FilePreviewer() {
  const [imagePreview, setImagePreview] = useState(null);
  const [videoPreview, setVideoPreview] = useState(null);
  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>
        <button className="btn">x</button>
      </div>
      <div className="preview">
        {imagePreview != null && <img src={imagePreview} alt="" />}
        {videoPreview != null && <video controls src={videoPreview}></video>}
      </div>
    </div>
  );
}

That's all we need to create a working file Previewer. It can preview an image and a video.

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

Code Sandbox

Warning

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.

Jatin's Newsletter

I write monthly Tech, Web Development and chrome extension that will improve your productivity. Trust me, I won't spam you.

Share on Social Media: