Pure FormData implementation designed for Node.js environments with full HTML5 specification compatibility and minimal dependencies. This module provides a standalone FormData class that works seamlessly with modern HTTP libraries like node-fetch.
A complete implementation of the HTML5 FormData interface for Node.js environments.
/**
* Creates a new FormData instance (ESM version does not accept form elements)
* @constructor
* @throws {TypeError} If any arguments are provided (ESM version only accepts empty constructor)
*/
class FormData {
constructor();
}Usage Example:
import { FormData } from "formdata-polyfill/esm.min.js";
const fd = new FormData();
// Ready to use with all standard FormData methods/**
* Custom instanceof check for FormData-like objects
* @param obj - Object to test
* @returns true if object implements FormData interface
*/
static [Symbol.hasInstance](obj: any): boolean;Usage Example:
import { FormData } from "formdata-polyfill/esm.min.js";
const fd = new FormData();
console.log(fd instanceof FormData); // true
// Also works with FormData-like objects
const mockFormData = {
append() {}, delete() {}, get() {}, getAll() {}, has() {}, set() {},
forEach() {}, entries() {}, keys() {}, values() {},
constructor() {}, [Symbol.toStringTag]: 'FormData'
};
console.log(mockFormData instanceof FormData); // trueAdds a new field to the FormData instance. If the field already exists, the new value is added without replacing existing values.
/**
* Appends a field to the FormData instance
* @param name - Field name
* @param value - Field value (string, Blob, or File)
* @param filename - Optional filename for Blob values
* @throws {TypeError} If fewer than 2 arguments are provided
*/
append(name: string, value: string | Blob | File, filename?: string): void;Usage Examples:
import { FormData, File } from "formdata-polyfill/esm.min.js";
const fd = new FormData();
// String values
fd.append("username", "john_doe");
fd.append("message", "Hello World");
// File values
const file = new File(["file content"], "document.txt", { type: "text/plain" });
fd.append("document", file);
// Blob with custom filename
const blob = new Blob(["binary data"], { type: "application/octet-stream" });
fd.append("data", blob, "custom-name.bin");Sets a field value, replacing any existing values for that field name.
/**
* Sets a field value, replacing existing values
* @param name - Field name
* @param value - Field value (string, Blob, or File)
* @param filename - Optional filename for Blob values
* @throws {TypeError} If fewer than 2 arguments are provided
*/
set(name: string, value: string | Blob | File, filename?: string): void;Usage Example:
const fd = new FormData();
fd.append("status", "draft");
fd.append("status", "pending");
fd.set("status", "published"); // Replaces both previous valuesRetrieves the first value for a given field name.
/**
* Gets the first value for a field name
* @param name - Field name to retrieve
* @returns First value or null if field doesn't exist
* @throws {TypeError} If no arguments are provided
*/
get(name: string): string | File | null;Usage Example:
const fd = new FormData();
fd.append("email", "user@example.com");
fd.append("email", "backup@example.com");
const primaryEmail = fd.get("email"); // "user@example.com"
const nonExistent = fd.get("phone"); // nullRetrieves all values for a given field name as an array.
/**
* Gets all values for a field name
* @param name - Field name to retrieve
* @returns Array of all values for the field
* @throws {TypeError} If no arguments are provided
*/
getAll(name: string): (string | File)[];Usage Example:
const fd = new FormData();
fd.append("tags", "javascript");
fd.append("tags", "nodejs");
fd.append("tags", "formdata");
const allTags = fd.getAll("tags"); // ["javascript", "nodejs", "formdata"]
const noTags = fd.getAll("categories"); // []Checks if a field exists in the FormData instance.
/**
* Checks if a field exists
* @param name - Field name to check
* @returns true if field exists, false otherwise
* @throws {TypeError} If no arguments are provided
*/
has(name: string): boolean;Usage Example:
const fd = new FormData();
fd.append("username", "john");
console.log(fd.has("username")); // true
console.log(fd.has("password")); // falseRemoves all fields with the given name from the FormData instance.
/**
* Deletes all fields with the given name
* @param name - Field name to delete
* @throws {TypeError} If no arguments are provided
*/
delete(name: string): void;Usage Example:
const fd = new FormData();
fd.append("temp", "value1");
fd.append("temp", "value2");
fd.append("keep", "important");
fd.delete("temp");
console.log(fd.has("temp")); // false
console.log(fd.has("keep")); // trueExecutes a callback function for each field in the FormData instance.
/**
* Executes a callback for each field
* @param callback - Function to execute for each field
* @param thisArg - Optional this context for callback
* @throws {TypeError} If no arguments are provided
*/
forEach(callback: (value: string | File, name: string, formData: FormData) => void, thisArg?: any): void;Usage Example:
const fd = new FormData();
fd.append("name", "John");
fd.append("age", "30");
fd.forEach((value, name) => {
console.log(`${name}: ${value}`);
});
// Output:
// name: John
// age: 30Provides iterator support for traversing FormData fields.
/**
* Returns an iterator of [name, value] pairs
*/
entries(): Iterator<[string, string | File]>;
/**
* Returns an iterator of field names
*/
keys(): Iterator<string>;
/**
* Returns an iterator of field values
*/
values(): Iterator<string | File>;
/**
* Default iterator (same as entries)
*/
[Symbol.iterator](): Iterator<[string, string | File]>;Usage Examples:
const fd = new FormData();
fd.append("a", "1");
fd.append("b", "2");
// Using entries()
for (const [name, value] of fd.entries()) {
console.log(`${name}: ${value}`);
}
// Using keys()
for (const name of fd.keys()) {
console.log(`Field: ${name}`);
}
// Using values()
for (const value of fd.values()) {
console.log(`Value: ${value}`);
}
// Using default iterator (for...of)
for (const [name, value] of fd) {
console.log(`${name}: ${value}`);
}Converts a FormData instance to a properly formatted multipart/form-data Blob.
/**
* Converts FormData to a multipart/form-data Blob
* @param formData - FormData instance to convert
* @param BlobClass - Optional Blob constructor (defaults to global Blob)
* @returns Blob with proper multipart encoding and boundary
*/
function formDataToBlob(formData: FormData, BlobClass?: typeof Blob): Blob;Usage Examples:
import { FormData, formDataToBlob, File } from "formdata-polyfill/esm.min.js";
import fetch from "node-fetch";
const fd = new FormData();
fd.append("name", "John Doe");
fd.append("file", new File(["content"], "test.txt"));
// Convert to blob for HTTP request
const blob = formDataToBlob(fd);
// Use with fetch
const response = await fetch("https://httpbin.org/post", {
method: "POST",
body: blob,
headers: {
"Content-Type": blob.type, // multipart/form-data; boundary=...
},
});
// Use with Node.js http module
import { Readable } from "node:stream";
import http from "node:http";
const stream = Readable.from(blob.stream());
const req = http.request("http://httpbin.org/post", {
method: "POST",
headers: {
"Content-Length": blob.size,
"Content-Type": blob.type,
},
});
stream.pipe(req);Re-exported File class from fetch-blob for creating File instances in Node.js.
/**
* File class for creating file objects in Node.js
* @param fileBits - Array of data chunks
* @param fileName - Name of the file
* @param options - File options including type and lastModified
*/
class File extends Blob {
constructor(fileBits: BlobPart[], fileName: string, options?: FilePropertyBag);
readonly name: string;
readonly lastModified: number;
}
interface FilePropertyBag extends BlobPropertyBag {
lastModified?: number;
}Usage Example:
import { File } from "formdata-polyfill/esm.min.js";
// Create a text file
const textFile = new File(["Hello, World!"], "greeting.txt", {
type: "text/plain",
lastModified: Date.now(),
});
// Create a binary file
const binaryData = new Uint8Array([0x89, 0x50, 0x4E, 0x47]);
const imageFile = new File([binaryData], "pixel.png", {
type: "image/png",
});
console.log(textFile.name); // "greeting.txt"
console.log(textFile.type); // "text/plain"
console.log(textFile.size); // 13The ESM module accepts file-like objects that implement the required interface, useful for streams from other sources.
/**
* File-like object interface (can be used instead of File instances)
*/
interface FileLike {
readonly size: number;
readonly type: string;
readonly name: string;
stream(): ReadableStream<Uint8Array>;
readonly [Symbol.toStringTag]: "File";
}Usage Example:
import { FormData } from "formdata-polyfill/esm.min.js";
const fd = new FormData();
// Append file-like object (useful for streams from other destinations)
fd.append('file-upload', {
size: 123,
type: 'video/mp4',
name: 'cat-video.mp4',
stream() {
// Return a ReadableStream from your source
return myStreamSource.getReadableStream();
},
[Symbol.toStringTag]: 'File'
});
// File-like objects work with formDataToBlob
const blob = formDataToBlob(fd);The module works seamlessly with fetch-blob utilities for file operations.
Usage Example:
import { FormData, formDataToBlob } from "formdata-polyfill/esm.min.js";
import { fileFromSync } from "fetch-blob/from.js";
const fd = new FormData();
// Load file from filesystem (Node.js)
const file = fileFromSync('./README.md');
fd.append('readme', file);
// Multiple file uploads
fd.append('file-upload', new File(['abc'], 'hello-world.txt'));
fd.append('file-upload', file);
// Convert to blob for HTTP request
const blob = formDataToBlob(fd);
console.log(blob.type); // multipart/form-data; boundary=...