Blog
Wild & Free Tools

Base64 Encoding Images in React and TypeScript — Data URIs and File Uploads

Last updated: January 2, 2026 6 min read

Table of Contents

  1. Reading a File as Base64 with FileReader
  2. Extracting Just the Base64 String
  3. Sending Base64 Images to an API in React
  4. Inline Base64 Data URIs in JSX
  5. Drag and Drop File Upload with Base64 Preview
  6. Frequently Asked Questions

React and TypeScript applications commonly need Base64 image encoding for three scenarios: generating image previews before upload, sending images to APIs that accept Base64 payloads, and embedding small icons as data URIs in JSX. This guide covers each pattern with working TypeScript code.

Reading a User-Selected File as Base64 (FileReader API)

The browser's FileReader API converts a File object (from an input element) to a Base64 data URI:

import { useState } from 'react';

function useBase64File() {
  const [base64, setBase64] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);

  const readFile = (file: File): Promise<string> =>
    new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = (e) => resolve(e.target?.result as string);
      reader.onerror = () => reject(new Error('Failed to read file'));
      reader.readAsDataURL(file);
    });

  const handleFile = async (file: File) => {
    try {
      const result = await readFile(file);
      setBase64(result);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error');
    }
  };

  return { base64, error, handleFile };
}

// Usage in a component
function ImageUpload() {
  const { base64, error, handleFile } = useBase64File();

  return (
    <div>
      <input
        type="file"
        accept="image/*"
        onChange={(e) => {
          const file = e.target.files?.[0];
          if (file) handleFile(file);
        }}
      />
      {base64 && <img src={base64} alt="Preview" style={{ maxWidth: 300 }} />}
      {error && <p style={{ color: 'red' }}>{error}</p>}
    </div>
  );
}

The readAsDataURL method returns a full data URI including the MIME type prefix: data:image/png;base64,iVBORw0KGgo.... This is ready to use directly in an img src attribute.

Getting Just the Base64 String (Without the Data URI Prefix)

When sending to an API, you usually want the Base64 string alone, without the data:image/png;base64, prefix. Strip it with a simple split:

// Full data URI: "data:image/png;base64,iVBORw0KGgo..."
const dataUri = await readFile(file);

// Option 1: Split on comma (works for any image type)
const base64Only = dataUri.split(',')[1];

// Option 2: Replace with regex (more explicit)
const base64Only = dataUri.replace(/^data:image/[a-z]+;base64,/, '');

// Option 3: Keep both parts accessible
const [prefix, base64Only] = dataUri.split(',');
const mimeType = prefix.match(/data:([^;]+)/)?.[1]; // "image/png"

When posting to an API, send the base64-only string unless the API specifically expects the full data URI prefix. Always check the API documentation — some want the prefix, most do not.

Sell Custom Apparel — We Handle Printing & Free Shipping

Sending a Base64 Image to an API

interface UploadPayload {
  filename: string;
  mimeType: string;
  data: string; // Base64-encoded image content
}

async function uploadImageAsBase64(file: File): Promise<void> {
  const dataUri = await readFile(file);
  const [prefix, base64Data] = dataUri.split(',');
  const mimeType = prefix.match(/data:([^;]+)/)?.[1] ?? 'image/jpeg';

  const payload: UploadPayload = {
    filename: file.name,
    mimeType,
    data: base64Data,
  };

  const response = await fetch('/api/images/upload', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });

  if (!response.ok) {
    throw new Error('Upload failed');
  }
}

For files larger than ~5MB, prefer multipart form data over Base64 JSON — FormData with a fetch POST is more memory-efficient and supports streaming on the server side. Base64 JSON is ideal for smaller images like avatars, thumbnails, and icons.

Inline Base64 Images as Data URIs in JSX

For small static images you want to ship with your component — icons, logos, small decorative elements — you can embed them as Base64 data URIs directly in TypeScript/JSX:

// A tiny 1x1 transparent PNG as a placeholder
const PLACEHOLDER_IMAGE =
  "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";

// Inline SVG as Base64
const LOGO_BASE64 =
  "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==";

function Avatar({ src }: { src?: string }) {
  return (
    <img
      src={src ?? PLACEHOLDER_IMAGE}
      alt="User avatar"
      onError={(e) => { e.currentTarget.src = PLACEHOLDER_IMAGE; }}
    />
  );
}

Keep inline Base64 images small — under 5KB for icons, under 2KB for placeholder images. Large Base64 strings in JavaScript bundles increase bundle size and are not cached separately like external image files.

Drag and Drop Image Upload with Base64 Preview

function DropZone() {
  const [preview, setPreview] = useState<string | null>(null);
  const [isDragging, setIsDragging] = useState(false);

  const processFile = (file: File) => {
    if (!file.type.startsWith('image/')) return;
    const reader = new FileReader();
    reader.onload = (e) => setPreview(e.target?.result as string);
    reader.readAsDataURL(file);
  };

  return (
    <div
      onDragOver={(e) => { e.preventDefault(); setIsDragging(true); }}
      onDragLeave={() => setIsDragging(false)}
      onDrop={(e) => {
        e.preventDefault();
        setIsDragging(false);
        const file = e.dataTransfer.files[0];
        if (file) processFile(file);
      }}
      style={{
        border: isDragging ? '2px solid #58a6ff' : '2px dashed #444',
        padding: 40,
        textAlign: 'center',
        borderRadius: 8,
      }}
    >
      {preview ? (
        <img src={preview} alt="Preview" style={{ maxWidth: '100%' }} />
      ) : (
        <p>Drop an image here</p>
      )}
    </div>
  );
}

Try It Free — No Signup Required

Runs 100% in your browser. No data is collected, stored, or sent anywhere.

Open Free Base64 Encoder/Decoder

Frequently Asked Questions

Should I send images as Base64 or FormData from React?

Use Base64 JSON for small images (under 5MB) when your API expects JSON payloads. Use FormData for larger files, video, or when your server handles multipart uploads — it is more memory-efficient and avoids the 33% Base64 overhead. If your API accepts both, FormData is generally the better choice for files.

How do I convert a Base64 string back to a File object in React?

Use the fetch API to convert a data URI to a Blob: fetch(dataUri).then(r => r.blob()).then(blob => new File([blob], filename, { type: blob.type })). This reconstructs a proper File object from a Base64 data URI.

Can I use Base64 images with Next.js Image component?

Next.js Image does not accept data URI strings as the src — it expects a URL path. Use a regular img tag for Base64 data URIs. You can use the blurDataURL prop on the Next.js Image component for Base64 blur placeholders (a special supported use case).

Jake Morrison
Jake Morrison Security & Systems Engineer

Jake has spent a decade on client-side security architecture. His conviction that files should never touch a third-party server is the foundation of WildandFree's zero-upload design.

More articles by Jake →
Launch Your Own Clothing Brand — No Inventory, No Risk