DEV Community

Cover image for QuickLook Integration in a Tauri App — Native macOS File Preview
hiyoyo
hiyoyo

Posted on

QuickLook Integration in a Tauri App — Native macOS File Preview

All tests run on an 8-year-old MacBook Air. All results from shipping 7 Mac apps as a solo developer. No sponsored opinion.

HiyokoKit's MTP file manager includes QuickLook preview. Press Space, see the file. Native macOS behavior in a Tauri app. Here's how it works — and why it's worth doing.


What QuickLook Is

QuickLook is macOS's built-in file preview system. Press Space on any file in Finder — that's QuickLook. It handles images, PDFs, videos, and documents without opening separate apps.

For a file manager, QuickLook preview is table stakes on macOS. Users expect it. If it's missing, the app feels unfinished.


Triggering QuickLook from Rust

The qlmanage command-line tool can trigger QuickLook from any process:

use std::process::Command;

#[tauri::command]
async fn preview_file(file_path: String) -> Result<(), AppError> {
    Command::new("qlmanage")
        .args(["-p", &file_path])
        .spawn()
        .map_err(|e| AppError::Preview(e.to_string()))?;

    Ok(())
}
Enter fullscreen mode Exit fullscreen mode

qlmanage -p opens a native QuickLook preview window for the specified path. That's it on the Rust side for local files.


For MTP Files: Download First, Preview, Cleanup

Files on an Android device don't have a local path — they live on the device over MTP. The flow is: download to a temp file → preview → clean up.

#[tauri::command]
async fn preview_mtp_file(
    device_path: String,
    filename: String,
) -> Result<(), AppError> {
    // Download to temp
    let temp_path = std::env::temp_dir().join(&filename);
    download_from_device(&device_path, &temp_path).await?;

    // Open QuickLook
    Command::new("qlmanage")
        .args(["-p", temp_path.to_str().unwrap()])
        .spawn()?;

    // Schedule cleanup after delay
    let temp_clone = temp_path.clone();
    tokio::spawn(async move {
        tokio::time::sleep(Duration::from_secs(30)).await;
        std::fs::remove_file(temp_clone).ok();
    });

    Ok(())
}
Enter fullscreen mode Exit fullscreen mode

30 seconds gives the user time to view before cleanup. For large files (RAW photos, videos), you may want to increase this — or tie cleanup to a window-close event instead.


The Keyboard Shortcut

QuickLook's native feel requires Space to trigger it. Wire it up in the frontend:

useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
        if (e.code === 'Space' && selectedFile) {
            e.preventDefault()
            invoke('preview_file', { filePath: selectedFile.path })
        }
    }

    window.addEventListener('keydown', handleKeyDown)
    return () => window.removeEventListener('keydown', handleKeyDown)
}, [selectedFile])
Enter fullscreen mode Exit fullscreen mode

Space on selected file → QuickLook preview. Matches Finder behavior exactly. Users don't have to think about it.


The Verdict

QuickLook integration is 10 lines of Rust and 10 lines of TypeScript. The UX improvement is significant — native preview in a third-party file manager feels right in a way that a custom preview panel never quite does.

If you're building a file manager or any app that works with files on macOS, implement this. It's one of those features that costs almost nothing to add and immediately makes the app feel professional.


If this was useful, a ❤️ helps more than you'd think!

👉 HiyokoKit → https://hiyokomtp.lemonsqueezy.com/checkout/buy/2c94dd0f-e28a-4a17-8efc-7bd93087d46d

X → @hiyoyok

Top comments (1)

Collapse
 
hiyoyok profile image
hiyoyo

TL;DR:
・qlmanage -p triggers native QuickLook from Rust — no Swift or Objective-C needed
・MTP files: download to temp → preview → cleanup after 30s with tokio::spawn
・Bind Space key in the frontend and it feels exactly like Finder
・Total implementation: ~10 lines Rust + ~10 lines TypeScript