Image upload in Next.js with Base64 encoding

I'll show you how to upload images in Next.js with Base64 encoding. We will use the next/image component to display the base64 encoded image.

Let's build a simple form to upload an image.

import type { NextPage } from "next";
import Image from "next/image";
import { useState } from "react";

const Upload: NextPage = () => {
  // State to store the file
  const [file, setFile] = useState<File | null>(null);

  // State to store the base64
  const [base64, setBase64] = useState<string | null>(null);

  return (
    <>
      <h1>Upload Image</h1>
      <form method="POST" encType="multipart/form-data">
        <input type="file" name="avatar" accept="image/*" />
        <button type="submit">Upload</button>
      </form>
    </>
  );
};

export default Upload;

Add a method to handle the file change event.

// When the file is selected, set the file state
const onFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  if (!e.target.files) {
    return;
  }

  setFile(e.target.files[0]);
};

Add another method to handle the click event.

// On click, clear the input value
const onClick = (e: React.MouseEvent<HTMLInputElement>) => {
  e.currentTarget.value = "";
};

Now let's add the toBase64 method to convert the file to base64.

// Convert a file to base64 string
const toBase64 = (file: File) => {
  return new Promise((resolve, reject) => {
    const fileReader = new FileReader();

    fileReader.readAsDataURL(file);

    fileReader.onload = () => {
      resolve(fileReader.result);
    };

    fileReader.onerror = (error) => {
      reject(error);
    };
  });
};

Next add the method to handle the form submit event.

// On submit, upload the file
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
  e.preventDefault();

  if (!file) {
    return;
  }

  // Convert the file to base64
  const base64 = await toBase64(file as File);

  setBase64(base64 as string);

  // You can upload the base64 to your server here
  await fetch("/api/your-upload-endpoint", {
    method: "POST",
    body: JSON.stringify({ base64 }),
    headers: {
      "Content-Type": "application/json",
    },
  });

  // Clear the states after upload
  setFile(null);
  setBase64(null);
};

Wire up the methods to handle the file change and click events.

<form method="POST" encType="multipart/form-data" onSubmit={handleSubmit}>
  <input
    type="file"
    name="avatar"
    accept="image/*"
    onChange={onFileChange}
    onClick={onClick}
  />
  <button type="submit">Upload</button>
</form>

Finally, let's add the Image component to display the base64 encoded image.

{
  base64 && (
    <Image src={base64} width={300} height={400} alt="Uploaded Image" />
  );
}

Here's the complete code for the upload form component.

import type { NextPage } from "next";
import Image from "next/image";
import { useState } from "react";

const Upload: NextPage = () => {
  // State to store the file
  const [file, setFile] = useState<File | null>(null);

  // State to store the base64
  const [base64, setBase64] = useState<string | null>(null);

  // When the file is selected, set the file state
  const onFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (!e.target.files) {
      return;
    }

    setFile(e.target.files[0]);
  };

  // On click, clear the input value
  const onClick = (e: React.MouseEvent<HTMLInputElement>) => {
    e.currentTarget.value = "";
  };

  // On submit, upload the file
  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    if (!file) {
      return;
    }

    // Convert the file to base64
    const base64 = await toBase64(file as File);

    setBase64(base64 as string);

    // You can upload the base64 to your server here
    await fetch("/api/your-upload-endpoint", {
      method: "POST",
      body: JSON.stringify({ base64 }),
      headers: {
        "Content-Type": "application/json",
      },
    });

    // Clear the states after upload
    setFile(null);
    setBase64(null);
  };

  return (
    <>
      <h1>Upload Image</h1>
      <form method="POST" encType="multipart/form-data" onSubmit={handleSubmit}>
        <input
          type="file"
          name="avatar"
          accept="image/*"
          onChange={onFileChange}
          onClick={onClick}
        />
        <button type="submit">Upload</button>
      </form>
      {base64 && (
        <Image src={base64} width={300} height={400} alt="Uploaded Image" />
      )}
    </>
  );
};

// Convert a file to base64 string
const toBase64 = (file: File) => {
  return new Promise((resolve, reject) => {
    const fileReader = new FileReader();

    fileReader.readAsDataURL(file);

    fileReader.onload = () => {
      resolve(fileReader.result);
    };

    fileReader.onerror = (error) => {
      reject(error);
    };
  });
};

export default Upload;