Get a List of All Files in a Folder And All Subfolders using Electron and React
Add to your RSS feed9 November 20233 min readTable of Contents
To get a list of all files in a folder and its subfolders using Electron and React, you can use the Input Event to read the directory and file information. Here's a basic example of how you can achieve this:
1. First, make sure you have Electron and React installed in your project:
npm create @quick-start/electronThen follow the prompts!
1 ✔ Project name: … <electron-app>2 ✔ Select a framework: › react3 ✔ Add TypeScript? … Yes4 ✔ Add Electron updater plugin? … No5 ✔ Enable Electron download mirror proxy? … No67 Done.
2. Add Tailwind to Electron:
npm install -D tailwindcssthen...
npx tailwindcss initConfigure your template paths
Add the paths to all of your template files in your tailwind.config.js file.
1 /** @type {import('tailwindcss').Config} */2 module.exports = {3 content: ['./src/renderer/index.html', './src/renderer/src/**/*.{js,ts,jsx,tsx}'],4 };
Add the Tailwind directives to your src/renderer/src/assets/index.css files
1 @tailwind base;2 @tailwind components;3 @tailwind utilities;
Now add postcss.config.js file to your root directory.
1 module.exports = {2 plugins: {3 tailwindcss: {},4 },5 };
Modify your src/preload/index.ts
file to set an api route
1 import { contextBridge } from 'electron';2 import { electronAPI } from '@electron-toolkit/preload';3 import * as fs from 'fs';45 const api = {6 readdirS: async (path: string): Promise<Dirent[]> =>7 await fs.readdirSync(path, { encoding: 'utf-8', withFileTypes: true }),8 isDirectory: (path: string): boolean => fs.lstatSync(path).isDirectory(),9 };1011 if (process.contextIsolated) {12 try {13 contextBridge.exposeInMainWorld('electron', electronAPI);14 contextBridge.exposeInMainWorld('api', api);15 } catch (error) {16 console.error(error);17 }18 } else {19 // @ts-ignore (define in dts)20 window.electron = electronAPI;21 // @ts-ignore (define in dts)22 window.api = api;23 }
Now add this code to App.ts inside the renderer folder
1 import { useState } from 'react'23 function App(): JSX.Element {4 const [files, setFiles] = useState<string[]>([])56 const folderOnChange = async (e: ChangeEvent<HTMLInputElement>) => {7 if (!e.target.files?.length) return8 const files: FileList = e.target.files9 const folderPath = files[0].path10 const dotIdx = folderPath.lastIndexOf('\\')11 let folder12 if (!dotIdx) {13 folder = folderPath14 } else {15 folder = folderPath.substring(0, dotIdx)16 }17 const filesAndFolders = await getFiles(folder)18 setFiles(filesAndFolders)19 }20 async function getFiles(dir, files = []): string[] {21 // Get an array of all files and directories in the passed directory using fs.readdirSync22 const fileList = await api.readdirS(dir)23 // Create the full path of the file/directory by concatenating the passed directory and file/directory name24 for (const file of Array.from(fileList)) {25 const name = `${dir}\\${file.name}`26 // Check if the current file/directory is a directory using fs.statSync27 if (api.isDirectory(name)) {28 // If it is a directory, recursively call the getFiles function with the directory path and the files array29 getFiles(name, files)30 } else {31 // If it is a file, push the full path to the files array32 files.push(name)33 }34 }35 return files36 }37 return (38 <div className="container">39 <div className="flex items-center justify-center w-full mt-5">40 <label41 className="flex items-center justify-center w-[216px] h-[45px] border border-gray-300 border-dashed42 rounded-lg cursor-pointer43 bg-gray-100 hover:bg-gray-250 dark:hover:bg-bray-400 dark:bg-gray-500 dark:hover:bg-gray-25044 hover:shadow-lg dark:hover:shadow-gray-400 hover:rotate-44"45 >46 <svg47 width="24"48 height="24"49 viewBox="0 0 24 24"50 fill="none"51 xmlns="http://www.w3.org/2000/svg"52 >53 <path54 d="M12 10V16M15 13H9M22 10V17C22 19.2091 20.2091 21 18 21H6C3.79086 21 2 19.2091 2 17V7C2 4.79086 3.79086 3 6 3H8.66667C9.53215 3 10.3743 3.28071 11.0667 3.8L12.9333 5.2C13.6257 5.71929 14.4679 6 15.3333 6H18C20.2091 6 22 7.79086 22 10Z"55 stroke="currentColor"56 strokeWidth="1.5"57 strokeLinecap="round"58 strokeLinejoin="round"59 className="stroke-gray-500 dark:stroke-gray-400"60 />61 </svg>6263 <p className="mb-1 pl-2 text-sm text-gray-500 dark:text-gray-400">64 <span className="font-semibold">Select a folder</span>65 </p>66 <input67 type="file"68 className="hidden"69 directory=""70 webkitdirectory=""71 onChange={folderOnChange}72 />73 </label>74 </span>7576 <div className="relative overflow-x-auto">77 <table className="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">78 <thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">79 <tr>80 <th scope="col" className="px-6 py-3">81 File name82 </th>83 </tr>84 </thead>85 <tbody>86 {files.length > 0 &&87 files.map((file) => {88 return (89 <tr90 className="bg-white border-b dark:bg-gray-800 dark:border-gray-700"91 key={file}92 >93 <th94 scope="row"95 className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"96 >97 {file}98 </th>99 </tr>100 )101 })}102 </tbody>103 </table>104 </span>105 </span>106 )107 }108109 export default App
Run your app:
npm run devThis example assumes that you have a basic understanding of Electron and React. Also, note that this example doesn't handle errors, and in a production environment, you should implement error handling for better robustness.