dimah-s3v1.5.5

useDownload

Headless React hook for presigned S3 downloads with browser navigation, fetch streams, and inline preview.

useDownload requests signed GET URLs from your server and handles browser-native downloads or client-side fetch streaming with live progress tracking.

components/download-avatar.tsx
"use client";

import { useDownload } from "@dimah-s3/react";

export function DownloadAvatar({ avatarKey }: { avatarKey: string }) {
  const { download, isPending } = useDownload({
    route: "avatar",
  });

  return (
    <button
      type="button"
      onClick={() => void download(avatarKey)}
      disabled={isPending}
      className="btn"
    >
      {isPending ? "Generating link…" : "Download Avatar"}
    </button>
  );
}

Download modes

Browser navigation (mode: "navigate", default)

Requests a presigned GET URL and navigates the browser directly to S3. S3 immediately responds with the binary file stream and triggers the browser's native file save dialog.

const { download, presign, phase, isPending } = useDownload({
  route: "avatar",
  onInitiated: (key) => {
    console.log("Browser handed download URL for:", key);
  },
});

// Trigger download
await download(avatarKey);

// Or get the presigned URL directly without triggering browser navigation
const { url, expiresIn } = await presign(avatarKey);

Fetch streaming (mode: "fetch")

Fetches the object bytes through a client-side fetch stream. Provides fine-grained byte progress, speed calculation, and abortable cancellation.

const { download, cancel, progress, isDownloading, isPending } = useDownload({
  route: "document",
  mode: "fetch",
  onProgress: (key, progress) => {
    console.log(
      `Downloaded ${progress.percent}% (${progress.loaded}/${progress.total})`,
    );
  },
  onSuccess: (key, fileName) => {
    console.log(`Saved ${fileName} to disk`);
  },
});

return (
  <div>
    <button onClick={() => void download(documentKey)} disabled={isPending}>
      {isDownloading ? `Downloading: ${progress.percent}%` : "Download File"}
    </button>
    {isDownloading && (
      <button type="button" onClick={cancel}>
        Cancel
      </button>
    )}
  </div>
);

Inline preview with useObjectUrl

For displaying private S3 files inline (e.g. <img>, <video>, <audio>, or <iframe>), use useObjectUrl. It requests a signed URL with disposition: "inline" and automatically caches the signed URL in memory until shortly before its expiration window.

components/avatar-image.tsx
"use client";

import { useObjectUrl } from "@dimah-s3/react";

export function AvatarImage({ avatarKey }: { avatarKey: string }) {
  const { url, isLoading, refresh } = useObjectUrl({
    route: "avatar",
    objectKey: avatarKey,
    disposition: "inline",
  });

  if (isLoading)
    return <div className="size-16 rounded-full bg-muted animate-pulse" />;
  if (!url) return null;

  return (
    <img
      src={url}
      alt="User Avatar"
      className="size-16 rounded-full object-cover"
    />
  );
}

Type reference

import type {
  UseNavigateDownloadOptions,
  UseNavigateDownloadReturn,
  UseFetchDownloadOptions,
  UseFetchDownloadReturn,
  UseObjectUrlOptions,
  UseObjectUrlReturn,
} from "@dimah-s3/react";

UseNavigateDownloadOptions

Prop

Type


UseFetchDownloadOptions

Prop

Type


UseNavigateDownloadReturn

Prop

Type


UseFetchDownloadReturn

Prop

Type


UseObjectUrlOptions

Prop

Type


UseObjectUrlReturn

Prop

Type

Frequently asked questions

On this page