Documentation Index
Fetch the complete documentation index at: https://mintlify.com/l-xiaoshen/handstage/llms.txt
Use this file to discover all available pages before exploring further.
locator.setInputFiles(files) sets the selected files on an <input type="file"> DOM element. You obtain a locator from a frame, point it at the file input, and then call setInputFiles with whatever file data you have available. Chrome dispatches change and input events on the element after the files are assigned.
Getting a locator
Create a locator pointing at the file input element using page.locator():
import { V3 } from "@handstage/core"
const handstage = await V3.connectLocal()
const page = handstage.context.activePage()
await page.goto("https://example.com/upload")
const input = page.locator('input[type="file"]')
setInputFiles accepts four forms for the files argument.
1. A single file path
Pass a string containing the absolute path to a local file:
await input.setInputFiles("/home/user/documents/report.pdf")
2. An array of file paths
Pass an array of absolute paths to select multiple files at once:
await input.setInputFiles([
"/home/user/photos/image1.jpg",
"/home/user/photos/image2.jpg",
])
The <input> element must have the multiple attribute set to accept more than one file. The browser may silently ignore extra files if the input does not support multiple selection.
3. An in-memory payload object
When you have file data in memory (for example, from a database, an API response, or a generated file), pass a payload object with name, mimeType, and buffer:
import fs from "fs/promises"
const pdfBuffer = await fs.readFile("/tmp/generated.pdf")
await input.setInputFiles({
name: "generated.pdf",
mimeType: "application/pdf",
buffer: pdfBuffer, // Buffer, Uint8Array, ArrayBuffer, or base64 string
})
The buffer field accepts:
Buffer (Node.js)
Uint8Array
ArrayBuffer
string — interpreted as base64-encoded file content
The optional lastModified field sets the file’s last-modified timestamp in milliseconds since the Unix epoch.
4. An array of payload objects
Upload multiple in-memory files at once:
await input.setInputFiles([
{
name: "avatar.png",
mimeType: "image/png",
buffer: avatarBuffer,
},
{
name: "resume.docx",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
buffer: resumeBuffer,
},
])
Clear the file selection
Pass an empty array to clear the current file selection:
await input.setInputFiles([])
File size limit
Each file passed as a payload object (not a local path) is subject to a 50 MB size limit per file. Exceeding this limit throws a HandstagesInvalidArgumentError:
setInputFiles(): file "large-video.mp4" is larger than the 50MB limit for remote uploads
The 50 MB limit applies when Handstage is connected to a remote browser (one that cannot see your local filesystem). For local browsers with a local file path, there is no SDK-level size restriction, though the operating system and Chrome’s own limits still apply.
Complete example
import { V3 } from "@handstage/core"
import fs from "fs/promises"
const handstage = await V3.connectLocal()
const page = handstage.context.activePage()
await page.goto("https://example.com/upload")
const frame = page.mainFrame()
const fileInput = frame.locator('input[type="file"]#document-upload')
// Option A: upload from disk
await fileInput.setInputFiles("/home/user/invoice.pdf")
// Option B: upload from memory
const csvData = Buffer.from("name,age\nAlice,30\nBob,25")
await fileInput.setInputFiles({
name: "users.csv",
mimeType: "text/csv",
buffer: csvData,
})
// Submit the form
const submitButton = frame.locator('button[type="submit"]')
await submitButton.click()
await handstage.close()
After calling setInputFiles, Chrome automatically dispatches change and input events on the element. If your application listens to those events to update its UI or enable the submit button, they will fire without any extra steps.