Working with Base64 in JavaScript

Complete guide to encoding and decoding Base64 in JavaScript, including handling Unicode and binary data.

javascripttutorialcode

Base64 in JavaScript

JavaScript provides built-in functions for Base64 encoding, but there are important nuances to understand.

Built-in Functions

// Encoding
const encoded = btoa("Hello"); // "SGVsbG8="

// Decoding
const decoded = atob("SGVsbG8="); // "Hello"

The Unicode Problem

btoa() only works with ASCII characters. For Unicode text, you need extra steps:
// Encoding Unicode
function encodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(
/%([0-9A-F]{2})/g,
(_, p1) => String.fromCharCode('0x' + p1)
));
}

// Decoding Unicode
function decodeUnicode(str) {
return decodeURIComponent(atob(str).split('').map(
c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
).join(''));
}

Modern Approach with TextEncoder

// Encoding with TextEncoder (handles Unicode properly)
function toBase64(str) {
const bytes = new TextEncoder().encode(str);
const binString = Array.from(bytes, b =>
String.fromCodePoint(b)
).join("");
return btoa(binString);
}

// Decoding
function fromBase64(base64) {
const binString = atob(base64);
const bytes = Uint8Array.from(binString, c =>
c.codePointAt(0)
);
return new TextDecoder().decode(bytes);
}

Working with Files

// Convert File to Base64
async function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
});
}

// Usage
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async (e) => {
const base64 = await fileToBase64(e.target.files[0]);
console.log(base64); // "data:image/png;base64,iVBORw0..."
});

Frequently Asked Questions

Common questions about this topic

btoa() only accepts characters in the Latin1 range (0-255). Unicode characters like emoji or non-Latin scripts have code points above 255, causing 'InvalidCharacterError'. Use TextEncoder to convert to UTF-8 bytes first, then encode those bytes.

btoa/atob are browser APIs that work with strings. Node.js Buffer is more versatile, handling various encodings and binary data directly. Use Buffer.from(string).toString('base64') in Node.js for better Unicode support and performance.

Use FileReader.readAsDataURL() for a complete data URL, or FileReader.readAsArrayBuffer() followed by btoa() on the byte string. For large files, consider streaming or chunked encoding to avoid memory issues.