Back to Blog

Tauri File Access: Build a Notes App with React & Rust

Sandy LaneSandy Lane

Video: Tauri File Access: Build a Notes App with React & Rust by Taught by Celeste AI - AI Coding Coach

Watch full page →

Tauri File Access: Build a Notes App with React & Rust

Learn how to build a simple notes app with Tauri that can open and save files directly on the user's file system. This tutorial demonstrates integrating Tauri's dialog and file system plugins to create native file pickers and read/write file content securely from a React frontend with a Rust backend.

Code

// src-tauri/src/main.rs (Rust backend)
#![cfg_attr(
  all(not(debug_assertions), target_os = "windows"),
  windows_subsystem = "windows"
)]

use tauri_plugin_dialog::DialogExt;
use tauri_plugin_fs::{FileSystemExt, FsScope};

fn main() {
  tauri::Builder::default()
    // Enable dialog plugin for native file pickers
    .plugin(tauri_plugin_dialog::init())
    // Enable fs plugin with read/write permissions
    .plugin(tauri_plugin_fs::init(FsScope::default()))
    .run(tauri::generate_context!())
    .expect("error while running tauri application");
}

// src/App.tsx (React frontend)
import React, { useState } from 'react';
import { open, save } from '@tauri-apps/plugin-dialog';
import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';

export default function App() {
  const [content, setContent] = useState('');

  // Open file picker and load text file content
  async function handleOpen() {
    const selected = await open({ multiple: false, filters: [{ name: 'Text Files', extensions: ['txt'] }] });
    if (typeof selected === 'string') {
      const fileContent = await readTextFile(selected);
      setContent(fileContent);
    }
  }

  // Show save dialog and write content to chosen file
  async function handleSave() {
    const path = await save({ filters: [{ name: 'Text Files', extensions: ['txt'] }] });
    if (path) {
      await writeTextFile({ path, contents: content });
    }
  }

  return (
    <>
      <textarea
        value={content}
        onChange={e => setContent(e.target.value)}
        rows={20}
        cols={60}
        placeholder="Write your notes here..."
      />
      <div>
        <button onClick={handleOpen}>Open</button>
        <button onClick={handleSave}>Save</button>
      </div>
    </>
  );
}

Key Points

  • Tauri plugins like dialog and fs enable native file pickers and secure file system access.
  • The Rust backend must initialize these plugins with appropriate permissions to allow reading and writing files.
  • The React frontend uses plugin APIs to open native dialogs and read or write text files asynchronously.
  • File paths returned from dialogs are passed to the fs plugin methods to perform file operations.
  • This setup provides a clean, native-feeling desktop app experience using React and Rust with Tauri.