shadimage
utilcn
componentdownload-filesource: ok · hit

Download A File From Storage

Download a file from a storage provider using a presigned download URL.

npx shadcn add "https://utilcn.dev/r/download-file.json"
free

No selection tags yet — empty means no evidence, not lack of support.

Dependencies

Bundle weight · light
iconslucide-react

Files2 · source cached 10/15/2026, 10:49:03 AM

registry/default/storage/download-file.tsx
'use client';

import { Download } from 'lucide-react';
import type { PropsWithChildren } from 'react';
import { cn } from '@/lib/utils';
import { useDownloadFile } from '@/registry/default/storage/use-download-file';

type DownloadFileProps = PropsWithChildren<{
  fileKey: string;
  fileName?: string;
  className?: string;
}>;

export function DownloadFile({
  fileKey,
  fileName,
  children,
  className,
}: DownloadFileProps) {
  const downloadFile = useDownloadFile();

  const handleDownload = () => {
    downloadFile.mutate(
      { fileKey, fileName },
      {
        onSuccess: (url: string) => {
          console.log('Download initiated:', url);
        },
        onError: (err: Error) => {
          console.error(`Download failed: ${(err as Error).message}`);
        },
      },
    );
  };

  return (
    <button
      className={cn('flex items-center gap-2', className)}
      disabled={downloadFile.isPending}
      onClick={handleDownload}
      type="button"
    >
      {children || (
        <>
          <Download className="mr-2 h-4 w-4" />
          {downloadFile.isPending ? 'Downloading...' : 'Download'}
        </>
      )}
    </button>
  );
}
registry/default/storage/use-download-file.ts
import { useMutation } from '@tanstack/react-query';

type DownloadArgs = {
  fileKey: string;
  fileName?: string;
};

export function useDownloadFile() {
  return useMutation({
    mutationFn: async ({ fileKey, fileName }: DownloadArgs) => {
      const downloadRes = await fetch('/api/downloads/presign', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ key: fileKey }),
      });

      if (!downloadRes.ok) throw new Error('Failed to get download URL');
      const { downloadUrl } = await downloadRes.json();

      const response = await fetch(downloadUrl);
      const blob = await response.blob();
      const url = window.URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = fileName || fileKey.split('/').pop() || 'download';
      document.body.appendChild(link);
      link.click();
      link.remove();
      window.URL.revokeObjectURL(url);

      return downloadUrl;
    },
  });
}

More from utilcn

Browse all components in this library →