Chrome Extension File Handling on ChromeOS: Complete Developer Guide (2026)
File Handling for Chrome Extensions on ChromeOS
ChromeOS 120 introduced a powerful capability: Chrome extensions can now register as file handlers, appearing in the Files app’s “Open with” context menu. This means users can open specific file types directly with your extension — just like native apps.
If your extension works with documents, images, data files, or any custom format, file handling integration makes it feel native on Chromebooks.
How It Works
- You declare which file types your extension handles in
manifest.json - ChromeOS adds your extension to the “Open with” menu for matching files
- When a user selects your extension, Chrome opens your designated HTML page
- Your JavaScript receives the file via the LaunchQueue API
Step 1: Configure File Handlers
Add the file_handlers array to your manifest:
{
"manifest_version": 3,
"name": "Markdown Viewer",
"version": "1.0",
"file_handlers": [
{
"action": "/viewer.html",
"name": "Markdown Viewer",
"accept": {
"text/markdown": [".md", ".mdx", ".markdown"]
}
},
{
"action": "/editor.html",
"name": "Markdown Editor",
"accept": {
"text/markdown": [".md", ".mdx"],
"text/plain": [".txt"]
}
}
],
"background": {
"service_worker": "service-worker.js"
}
}File Handler Properties
| Property | Required | Description |
|---|---|---|
action | Yes | Path to the HTML page that handles the file |
name | Yes | Display name in the “Open with” menu |
accept | Yes | Object mapping MIME types to file extensions |
You can register multiple handlers for different workflows — one for viewing, another for editing.
Step 2: Process Files with LaunchQueue
When ChromeOS opens your handler page, it passes the file through the LaunchQueue API:
// viewer.js
if ('launchQueue' in window) {
launchQueue.setConsumer(async (launchParams) => {
if (!launchParams.files || launchParams.files.length === 0) {
showEmptyState();
return;
}
for (const fileHandle of launchParams.files) {
const file = await fileHandle.getFile();
const content = await file.text();
renderMarkdown(content, file.name);
}
});
} else {
showError('File handling is not supported in this environment.');
}Working with FileSystemFileHandle
The launchParams.files array contains FileSystemFileHandle objects, which give you full File System Access API capabilities:
async function processFile(fileHandle) {
// Read the file
const file = await fileHandle.getFile();
const content = await file.text();
// Get metadata
console.log(`Name: ${file.name}`);
console.log(`Size: ${file.size} bytes`);
console.log(`Type: ${file.type}`);
console.log(`Modified: ${new Date(file.lastModified)}`);
return { content, metadata: { name: file.name, size: file.size } };
}Writing Back to the File
If you have an editor extension, you can write changes back:
async function saveFile(fileHandle, newContent) {
const writable = await fileHandle.createWritable();
await writable.write(newContent);
await writable.close();
}Complete Example: JSON Viewer Extension
manifest.json
{
"manifest_version": 3,
"name": "JSON Viewer",
"version": "1.0",
"file_handlers": [
{
"action": "/viewer.html",
"name": "View JSON",
"accept": {
"application/json": [".json"],
"application/ld+json": [".jsonld"]
}
}
]
}viewer.html
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: monospace; padding: 20px; background: #1e1e1e; color: #d4d4d4; }
.filename { color: #569cd6; font-size: 14px; margin-bottom: 12px; }
.json-key { color: #9cdcfe; }
.json-string { color: #ce9178; }
.json-number { color: #b5cea8; }
.json-boolean { color: #569cd6; }
pre { white-space: pre-wrap; line-height: 1.5; }
</style>
</head>
<body>
<div class="filename" id="filename"></div>
<pre id="output"></pre>
<script src="viewer.js"></script>
</body>
</html>viewer.js
if ('launchQueue' in window) {
launchQueue.setConsumer(async (launchParams) => {
if (!launchParams.files?.length) return;
const fileHandle = launchParams.files[0];
const file = await fileHandle.getFile();
const text = await file.text();
document.getElementById('filename').textContent = file.name;
try {
const parsed = JSON.parse(text);
document.getElementById('output').innerHTML = syntaxHighlight(
JSON.stringify(parsed, null, 2)
);
} catch (e) {
document.getElementById('output').textContent = `Invalid JSON: ${e.message}`;
}
});
}
function syntaxHighlight(json) {
return json.replace(
/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
(match) => {
let cls = 'json-number';
if (/^"/.test(match)) {
cls = /:$/.test(match) ? 'json-key' : 'json-string';
} else if (/true|false/.test(match)) {
cls = 'json-boolean';
}
return `<span class="${cls}">${match}</span>`;
}
);
}Requirements and Limitations
| Requirement | Detail |
|---|---|
| ChromeOS version | 120 or later |
| Manifest version | V3 only |
| Permissions | None required for file handling |
| File types | Any MIME type and extension combination |
| Multiple files | Supported — iterate launchParams.files |
Known Limitations
- ChromeOS only — This API is not available on Windows, macOS, or Linux Chrome
- No drag-and-drop — File handlers only work via the Files app context menu
- Single consumer — Only one
setConsumercall per page
What’s Next
File handling transforms your Chrome extension into a first-class citizen on ChromeOS. If your extension processes any type of file, this integration makes the user experience seamless.
Discover more ways to improve your extension at ExtensionBooster.
Share this article
Build better extensions with free tools
Icon generator, MV3 converter, review exporter, and more — no signup needed.
Related Articles
Building Accessible Chrome Extensions: Keyboard, Screen Reader, and WCAG Compliance
26% of US adults have disabilities. Make your Chrome extension accessible with focus traps, ARIA, keyboard nav, and WCAG 2.1 AA compliance.
I Built the Same Chrome Extension With 5 Different Frameworks. Here's What Actually Happened.
WXT vs Plasmo vs CRXJS vs Extension.js vs Bedframe. Real benchmarks, honest opinions, and the framework with 12K stars that's quietly dying.
5 Best Email Marketing Services to Grow Your Chrome Extension (2026)
Compare the top email marketing platforms for SaaS and Chrome extension developers. MailerLite, Mailchimp, Brevo, ActiveCampaign, and Drip reviewed.