-
Notifications
You must be signed in to change notification settings - Fork 0
useFileSystem
The useFileSystem hook provides a powerful "local-first" abstraction over the modern File System Access API. It allows your React application to prompt the user to open a file from their local hard drive, read its content, and continually save edits back to that exact file without prompting them to re-download a new copy every time.
Warning
Browser Compatibility: The File System Access API is currently only supported in Chromium-based browsers (Chrome, Edge, Opera, Brave). Firefox and Safari do not support it due to differing security models. This hook exposes an isSupported flag so you can gracefully degrade your UI.
Security Requirement: This API only works in a Secure Context (HTTPS or localhost).
This example demonstrates how to build a basic Markdown/Text editor that reads from and writes to the user's hard drive directly.
import { useFileSystem } from 'react-hook-lab';
function LocalTextEditor() {
const {
isSupported,
status,
file,
content,
error,
open,
save,
saveAs
} = useFileSystem({
accept: { 'text/plain': ['.txt', '.md'] },
description: "Text Files"
});
// Graceful degradation for unsupported browsers
if (!isSupported) {
return <div>Your browser does not support the File System Access API.</div>;
}
return (
<div>
<div className="toolbar">
<button onClick={() => open()} disabled={status === "picking"}>
Open File
</button>
{/* If a file is open, save() overwrites it. If no file is open, save() delegates to saveAs()! */}
<button
onClick={() => save(content || "")}
disabled={status === "saving"}
>
Save
</button>
<button onClick={() => saveAs(content || "", { suggestedName: "copy.txt" })}>
Save As...
</button>
</div>
{error && <p style={{ color: "red" }}>Error: {error.message}</p>}
{status === "reading" && <p>Loading file...</p>}
{file && (
<div className="editor">
<h3>Editing: {file.name} (Last modified: {new Date(file.lastModified).toLocaleString()})</h3>
<textarea
value={content || ""}
onChange={(e) => {
// Update local state (you'd typically manage this with useState in your component,
// but save() takes the new content to write to disk).
}}
rows={20}
cols={80}
/>
</div>
)}
</div>
);
}You can pass these options when initializing the hook, or override them when calling open(options) or saveAs(content, options).
-
accept: Record<string, string[]>: A map of MIME types to an array of extensions to filter the file picker. Example:{ 'image/png': ['.png'], 'text/html': ['.html', '.htm'] }. -
description: string: A human-readable description for the file types (e.g.,"Images"or"Text Files"). -
suggestedName: string: (Only applicable tosaveAs) Suggests a default file name in the Save dialog.
-
isSupported: boolean:trueifwindow.showOpenFilePickerexists in the current environment. -
status: "idle" | "picking" | "reading" | "saving" | "error": The current status of the file operation. -
file: File | null: The standard HTML5Fileobject containing metadata likename,size, andlastModified. -
handle: FileSystemFileHandle | null: The underlying handle to the file. -
content: string | null: The text content of the file (read automatically when opened). -
error: Error | null: The last error encountered. Note that user cancellations (AbortError) are caught silently and do not trigger an error state. -
open: (options?: UseFileSystemOptions) => Promise<void>: Opens the native file picker to read a file. -
save: (newContent: string | Blob, options?: UseFileSystemSaveAsOptions) => Promise<void>: Silently overwrites the currently opened file withnewContent. If no file is currently open, it automatically delegates tosaveAs()to prompt the user to create a new file. -
saveAs: (newContent: string | Blob, options?: UseFileSystemSaveAsOptions) => Promise<void>: Prompts the user to pick a new save location and writes the content to it, updating the activehandle. -
reset: () => void: Clears the currently opened file and resets the state to idle.
Built with ❤️ by Saurav-TB-Pandey. | Report an Issue | NPM