How to open a directory  |  Files and directories patterns  |  web.dev (2024)

  • Home
  • Patterns
  • Files and directories patterns
Stay organized with collections Save and categorize content based on your preferences.

Dealing with directories is not something you will cope with on a daily basis,but occasionally the use case arises, such as wanting to process all images in a directory.With the File System Access API, users can now open directories in the browserand decide if they need write access or not.

The modern way

Using the File System Access API's showDirectoryPicker() method

To open a directory, callshowDirectoryPicker(),which returns a promise with the picked directory. If you need write access, you can pass { mode: 'readwrite' } to the method.

Browser Support

  • How to open a directory | Files and directories patterns | web.dev (4) 86
  • How to open a directory | Files and directories patterns | web.dev (5) 86
  • How to open a directory | Files and directories patterns | web.dev (6) x
  • How to open a directory | Files and directories patterns | web.dev (7) x

Source

The classic way

Using the <input type="file" webkitdirectory> element

The <input type="file" webkitdirectory> element on a page allows the user to click it and opena directory. The trick now consists of inserting the element invisibly into a page with JavaScript and click it programmatically.

Browser Support

  • How to open a directory | Files and directories patterns | web.dev (8) 7
  • How to open a directory | Files and directories patterns | web.dev (9) 13
  • How to open a directory | Files and directories patterns | web.dev (10) 50
  • How to open a directory | Files and directories patterns | web.dev (11) 11.1

Source

Progressive enhancement

The method below uses the File System Access API when it's supportedand else falls back to the classic approach. In both cases the functionreturns a directory, but in case of where the File System Access APIis supported, each file object also has a FileSystemDirectoryHandle stored inthe directoryHandle property and a FileSystemFileHandle stored in the handle property,so you can optionally serialize the handles to disk.

const openDirectory = async (mode = "read") => { // Feature detection. The API needs to be supported // and the app not run in an iframe. const supportsFileSystemAccess = "showDirectoryPicker" in window && (() => { try { return window.self === window.top; } catch { return false; } })(); // If the File System Access API is supported… if (supportsFileSystemAccess) { let directoryStructure = undefined; // Recursive function that walks the directory structure. const getFiles = async (dirHandle, path = dirHandle.name) => { const dirs = []; const files = []; for await (const entry of dirHandle.values()) { const nestedPath = `${path}/${entry.name}`; if (entry.kind === "file") { files.push( entry.getFile().then((file) => { file.directoryHandle = dirHandle; file.handle = entry; return Object.defineProperty(file, "webkitRelativePath", { configurable: true, enumerable: true, get: () => nestedPath, }); }) ); } else if (entry.kind === "directory") { dirs.push(getFiles(entry, nestedPath)); } } return [ ...(await Promise.all(dirs)).flat(), ...(await Promise.all(files)), ]; }; try { // Open the directory. const handle = await showDirectoryPicker({ mode, }); // Get the directory structure. directoryStructure = getFiles(handle, undefined); } catch (err) { if (err.name !== "AbortError") { console.error(err.name, err.message); } } return directoryStructure; } // Fallback if the File System Access API is not supported. return new Promise((resolve) => { const input = document.createElement('input'); input.type = 'file'; input.webkitdirectory = true; input.addEventListener('change', () => { let files = Array.from(input.files); resolve(files); }); if ('showPicker' in HTMLInputElement.prototype) { input.showPicker(); } else { input.click(); } });};

Further reading

  • File System Access API

Demo

HTML

<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📂</text></svg>" /> <title>How to open a directory</title> </head> <body> <h1>How to open a directory</h1> <button type="button">Open directory</button> <pre></pre> </body></html>

CSS

 :root { color-scheme: dark light;}html { box-sizing: border-box;}*,*:before,*:after { box-sizing: inherit;}body { margin: 1rem; font-family: system-ui, sans-serif;} 

JS

 const button = document.querySelector('button');const pre = document.querySelector('pre');const openDirectory = async (mode = "read") => { // Feature detection. The API needs to be supported // and the app not run in an iframe. const supportsFileSystemAccess = "showDirectoryPicker" in window && (() => { try { return window.self === window.top; } catch { return false; } })(); // If the File System Access API is supported… if (supportsFileSystemAccess) { let directoryStructure = undefined; const getFiles = async (dirHandle, path = dirHandle.name) => { const dirs = []; const files = []; for await (const entry of dirHandle.values()) { const nestedPath = `${path}/${entry.name}`; if (entry.kind === "file") { files.push( entry.getFile().then((file) => { file.directoryHandle = dirHandle; file.handle = entry; return Object.defineProperty(file, "webkitRelativePath", { configurable: true, enumerable: true, get: () => nestedPath, }); }) ); } else if (entry.kind === "directory") { dirs.push(getFiles(entry, nestedPath)); } } return [ ...(await Promise.all(dirs)).flat(), ...(await Promise.all(files)), ]; }; try { const handle = await showDirectoryPicker({ mode, }); directoryStructure = getFiles(handle, undefined); } catch (err) { if (err.name !== "AbortError") { console.error(err.name, err.message); } } return directoryStructure; } // Fallback if the File System Access API is not supported. return new Promise((resolve) => { const input = document.createElement('input'); input.type = 'file'; input.webkitdirectory = true; input.addEventListener('change', () => { let files = Array.from(input.files); resolve(files); }); if ('showPicker' in HTMLInputElement.prototype) { input.showPicker(); } else { input.click(); } });};button.addEventListener('click', async () => { const filesInDirectory = await openDirectory(); if (!filesInDirectory) { return; } Array.from(filesInDirectory).forEach((file) => (pre.textContent += `${file.name}\n`));}); 

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2024-09-17 UTC.

How to open a directory  |  Files and directories patterns  |  web.dev (2024)
Top Articles
$75,000 a year is how much an hour?
Respawn Worked on Titanfall 3 for 10 Months Before Pivoting to Apex Legends, Ex-Dev Reveals - IGN
Kreme Delite Menu
Splunk Stats Count By Hour
Robinhood Turbotax Discount 2023
Us 25 Yard Sale Map
Blairsville Online Yard Sale
Flights to Miami (MIA)
Call of Duty: NEXT Event Intel, How to Watch, and Tune In Rewards
Craigslistdaytona
Geometry Escape Challenge A Answer Key
Oppenheimer Showtimes Near Cinemark Denton
Best Food Near Detroit Airport
Icommerce Agent
Fraction Button On Ti-84 Plus Ce
Google Doodle Baseball 76
Danforth's Port Jefferson
Is The Yankees Game Postponed Tonight
Www.publicsurplus.com Motor Pool
Ein Blutbad wie kein anderes: Evil Dead Rise ist der Horrorfilm des Jahres
Joan M. Wallace - Baker Swan Funeral Home
St Clair County Mi Mugshots
Holiday Gift Bearer In Egypt
Coomeet Premium Mod Apk For Pc
Slim Thug’s Wealth and Wellness: A Journey Beyond Music
The Listings Project New York
Unable to receive sms verification codes
Free T33N Leaks
Ordensfrau: Der Tod ist die Geburt in ein Leben bei Gott
Emuaid Max First Aid Ointment 2 Ounce Fake Review Analysis
Six Flags Employee Pay Stubs
Obsidian Guard's Skullsplitter
The Boogeyman Showtimes Near Surf Cinemas
Maxpreps Field Hockey
Kelly Ripa Necklace 2022
Skip The Games Grand Rapids Mi
Google Flights Orlando
Sabrina Scharf Net Worth
Gfs Ordering Online
2Nd Corinthians 5 Nlt
M&T Bank
10 Types of Funeral Services, Ceremonies, and Events » US Urns Online
Spurs Basketball Reference
Waco.craigslist
Clock Batteries Perhaps Crossword Clue
El Patron Menu Bardstown Ky
Pronósticos Gulfstream Park Nicoletti
Craigslist Cars For Sale By Owner Memphis Tn
Diccionario De Los Sueños Misabueso
Kindlerso
Latest Posts
Article information

Author: Edwin Metz

Last Updated:

Views: 6084

Rating: 4.8 / 5 (58 voted)

Reviews: 89% of readers found this page helpful

Author information

Name: Edwin Metz

Birthday: 1997-04-16

Address: 51593 Leanne Light, Kuphalmouth, DE 50012-5183

Phone: +639107620957

Job: Corporate Banking Technician

Hobby: Reading, scrapbook, role-playing games, Fishing, Fishing, Scuba diving, Beekeeping

Introduction: My name is Edwin Metz, I am a fair, energetic, helpful, brave, outstanding, nice, helpful person who loves writing and wants to share my knowledge and understanding with you.