What problem are you trying to solve?
Web apps increasingly generate files client-side (JSON exports, CSV reports, images) using Blob URLs. Transferring these to another page's file upload requires downloading to disk first, then dragging from the downloads bar — cluttering the filesystem for transient data. The natural gesture — drag the download link into an upload box — should just work, but currently the drag only carries a URL, not a File.
What solutions exist today?
- Download then drag: User clicks the link to download, then drags from the downloads bar into the upload box. Two steps, leaves files on disk.
- Chrome-only
DownloadURL: e.dataTransfer.setData('DownloadURL', 'mime:name:url') in a dragstart handler. Only works in Chrome, requires a real HTTP URL (not blob: or data:), and has been progressively restricted.
- Clipboard:
navigator.clipboard.writeText() on the source page, paste handler on the target page. Requires control of both pages, struggles with large payloads (10MB+), and is a copy-paste UX rather than drag-and-drop.
How would you solve it?
When a user drags an <a> element that has both a download attribute and a blob: or data: href, the browser automatically includes a File entry in the drag data store, alongside the existing text/uri-list and text/plain entries. The filename comes from the download attribute value. The MIME type comes from the Blob's type.
data: URLs: The browser does not expose the raw data: URL to the drop target. Instead, on dragstart it reserves a blob: URL scoped to the source page's origin. The text/uri-list entry contains this blob: URL. Actual decoding can be deferred until the drop target reads dataTransfer.files or fetches the blob: URL. This avoids URL length issues and unifies both schemes.
- Timing: The browser determines whether to include a File entry based on the element's
download attribute and href scheme at the time the drag is initiated, before dragstart fires. Modifications to the element during dragstart do not affect the drag data store.
- No new JS API: The browser populates the File, not page script. JS
dragstart handlers cannot replace or remove the browser-generated File. What you drag is exactly what a click would download.
- Opt-in/out: The
download attribute is the opt-in. Removing it restores current behavior. No new events, flags, or cancellation mechanisms are required.
- Backward compatible: Drop targets that only look for URLs still get URLs. Drop targets that check for files now also work. Nothing breaks.
- Memory: The File entry references the existing Blob — no copy required. If a
blob: URL is revoked during drag, the drop fails gracefully.
Anything else?
- Scope: Limited to
blob: and data: URLs. HTTP(S) URLs are excluded because they'd require a network fetch on dragstart.
data: backward compatibility: <a href="data:..." download> has no reliable behavior in current browsers (the download attribute is largely ignored for data: URLs due to their opaque origin), so there is no backward compatibility risk.
- Cross-origin: The
blob: URL created for a data: href is scoped to the source page's origin. Cross-origin drop targets should use dataTransfer.files rather than the URL.
- Security: The browser already trusts this content enough to write it to disk on click — including a File in the drag data store is no more privileged.
What problem are you trying to solve?
Web apps increasingly generate files client-side (JSON exports, CSV reports, images) using Blob URLs. Transferring these to another page's file upload requires downloading to disk first, then dragging from the downloads bar — cluttering the filesystem for transient data. The natural gesture — drag the download link into an upload box — should just work, but currently the drag only carries a URL, not a File.
What solutions exist today?
DownloadURL:e.dataTransfer.setData('DownloadURL', 'mime:name:url')in adragstarthandler. Only works in Chrome, requires a real HTTP URL (notblob:ordata:), and has been progressively restricted.navigator.clipboard.writeText()on the source page, paste handler on the target page. Requires control of both pages, struggles with large payloads (10MB+), and is a copy-paste UX rather than drag-and-drop.How would you solve it?
When a user drags an
<a>element that has both adownloadattribute and ablob:ordata:href, the browser automatically includes aFileentry in the drag data store, alongside the existingtext/uri-listandtext/plainentries. The filename comes from thedownloadattribute value. The MIME type comes from the Blob's type.data:URLs: The browser does not expose the rawdata:URL to the drop target. Instead, on dragstart it reserves ablob:URL scoped to the source page's origin. Thetext/uri-listentry contains thisblob:URL. Actual decoding can be deferred until the drop target readsdataTransfer.filesor fetches theblob:URL. This avoids URL length issues and unifies both schemes.downloadattribute and href scheme at the time the drag is initiated, beforedragstartfires. Modifications to the element duringdragstartdo not affect the drag data store.dragstarthandlers cannot replace or remove the browser-generated File. What you drag is exactly what a click would download.downloadattribute is the opt-in. Removing it restores current behavior. No new events, flags, or cancellation mechanisms are required.blob:URL is revoked during drag, the drop fails gracefully.Anything else?
blob:anddata:URLs. HTTP(S) URLs are excluded because they'd require a network fetch on dragstart.data:backward compatibility:<a href="data:..." download>has no reliable behavior in current browsers (thedownloadattribute is largely ignored fordata:URLs due to their opaque origin), so there is no backward compatibility risk.blob:URL created for adata:href is scoped to the source page's origin. Cross-origin drop targets should usedataTransfer.filesrather than the URL.