Skip to content

useDownload

Views run in sandboxed iframes where direct downloads (<a download>, URL.createObjectURL) are blocked. The useDownload hook returns a download function that asks the host to save one or more files to the user’s filesystem. The host shows a confirmation dialog before initiating the download.

import { useDownload } from "@usefractal/frac/web";
function ExportButton({ rows }: { rows: Row[] }) {
const { download } = useDownload();
const handleClick = async () => {
const csv = rows.map((r) => `${r.id},${r.name}`).join("\n");
const { isError } = await download({
contents: [
{
type: "resource",
resource: {
uri: "file:///orders.csv",
mimeType: "text/csv",
text: csv,
},
},
],
});
if (isError) {
// user cancelled, host denied or not supported
}
};
return <button onClick={handleClick}>Export CSV</button>;
}
{ download: (params: DownloadParams) => Promise<DownloadResult> }
  • contents: (EmbeddedResource | ResourceLink)[]: one or more resources to download.
  • isError?: boolean = true if the user cancelled or the host denied. Transport errors (timeout, lost connection) throw an exception.

For content generated in the view (CSV, JSON, markdown):

{
type: "resource",
resource: {
uri: "file:///export.json", // filename hint (last path segment)
mimeType: "application/json",
text: JSON.stringify(data, null, 2),
},
}

For binary data, pass base64 in blob:

{
type: "resource",
resource: {
uri: "file:///chart.png",
mimeType: "image/png",
blob: base64EncodedPng,
},
}

When the file already lives on a server, let the host fetch it directly:

{
type: "resource_link",
uri: "https://api.example.com/reports/q4.pdf",
name: "Q4 Report",
mimeType: "application/pdf",
}
  • Must be user-initiated (button click, menu action). Hosts will reject calls fired from effects on mount.
  • The uri is a filename hint: the host derives the suggested save name from the last path segment.
  • For large binary content (more than a few hundred KB), prefer resource_link over inlining base64.