Skip to main content
Views run in sandboxed iframes where direct downloads (<a download>, URL.createObjectURL) are blocked. useDownload hands the host one or more resources to write to the user’s device, so a view can save a file it produced.

Example

The view builds a CSV from the carousel’s products and hands the host an inline resource, then offers a server-hosted PDF as a resource link.
views/carousel.tsx
import { useDownload } from "skybridge/web";

function Carousel({ products }: { products: Product[] }) {
  const { download } = useDownload();

  const exportCsv = async () => {
    const csv = products
      .map((p) => `${p.id},${p.name},${p.price}`)
      .join("\n");
    try {
      const { isError } = await download({
        contents: [
          {
            type: "resource",
            resource: {
              uri: "file:///products.csv", // last segment is the suggested filename
              mimeType: "text/csv",
              text: csv,
            },
          },
        ],
      });
      if (isError) {
        console.warn("Export cancelled or not supported by this host");
      }
    } catch (err) {
      console.error("Download failed to complete", err);
    }
  };

  const saveSpecSheet = async (product: Product) => {
    await download({
      contents: [
        {
          type: "resource_link",
          uri: `https://shop.example.com/specs/${product.id}.pdf`,
          name: `${product.name} spec sheet`,
          mimeType: "application/pdf",
        },
      ],
    });
  };

  return (
    <div>
      <button onClick={exportCsv}>Export catalog</button>
      {products.map((p) => (
        <button key={p.id} onClick={() => saveSpecSheet(p)}>
          Save {p.name} spec
        </button>
      ))}
    </div>
  );
}

Returns

useDownload returns a single function.

download

download(params: DownloadParams): Promise<DownloadResult>;
Asks the host to save the resources in params. The promise resolves once the host responds, and rejects if the request times out or the connection is lost. params one or more resources to save, each carried inline or fetched by the host from a URL.
type DownloadParams = {
  contents: (EmbeddedResource | ResourceLink)[];
};
EmbeddedResource carries the file inline; resource holds the bytes as a UTF-8 text string or a base64 blob. The uri’s last segment sets the suggested filename.
type EmbeddedResource = {
  type: "resource";
  resource:
    | { uri: string; text: string; mimeType?: string; _meta?: Record<string, unknown> }
    | { uri: string; blob: string; mimeType?: string; _meta?: Record<string, unknown> };
  annotations?: Annotations; // standard MCP annotations
  _meta?: Record<string, unknown>;
};
ResourceLink points the host at a URL it fetches itself.
type ResourceLink = {
  type: "resource_link";
  uri: string;
  name: string;
  title?: string;
  description?: string;
  mimeType?: string;
  size?: number;
  annotations?: Annotations; // standard MCP annotations
  icons?: Icon[];
  _meta?: Record<string, unknown>;
};
The promise resolves with a DownloadResult:
type DownloadResult = {
  isError?: boolean;
};
isError is true when the download did not happen: the user cancelled, or the host denied it (including a host that lacks the download capability). It is absent or false on success. A request that fails to complete (timeout, lost connection) rejects the promise instead of setting this flag.

Handle Files

Move files in and out of your app

useFiles

Upload and resolve host-managed files

useOpenExternal

Open a link outside the view