@htmlbricks/hb-downloader
v0.76.5
Published
Opens `hb-dialog` while `uri` is set and downloads the resource with `XMLHttpRequest` as a blob: optional JSON `headers`, inferred or explicit `targetfilename`, `Content-Disposition` parsing when exposed by CORS, progress bar from `onprogress`, then trigg
Readme
hb-downloader
Category: utilities
Tags: utilities, files
Web component that opens an inner hb-dialog while a download URL is active, fetches the resource with XMLHttpRequest as a blob, shows Bulma progress feedback, then triggers a browser save (temporary object URL + programmatic <a download> click). It forwards modalShow from the dialog, and emits downloadComplete or downloadError when the transfer finishes or fails. Closing the dialog clears the request URL, aborts any in-flight XHR, and resets error state.
Dependencies
hb-dialog— used for the modal shell, title slot, and open/close lifecycle that drives the download.
Custom element
hb-downloader
Attributes and properties
In HTML, attributes are snake_case and values are strings (see project conventions: booleans as yes / no, objects as JSON strings, numbers as string digits). The dialog’s visibility is driven internally from uri: a non-empty uri turns the inner dialog on; a successful download or closing the dialog clears uri and related state.
| Name | Required | Description |
| --- | --- | --- |
| uri | Yes (to start a download) | URL of the resource to fetch with GET. If empty, no dialog is shown and no request runs. |
| downloadid | No | String passed through to the inner dialog’s id and used in event detail where applicable. |
| targetfilename | No | Suggested file name for the save dialog. If omitted and uri is set, a default is derived from the last path segment of uri (query string stripped). The server may still override this via Content-Disposition when that header is readable (see CORS below). |
| headers | No | Optional request headers. From an HTML attribute, pass a JSON object as a string, e.g. '{"Accept":"application/json"}'. The component parses JSON strings into a plain object before opening the request. |
| id | No | Optional identifier for the host element (typing only; not wired to download logic in the current markup). |
| style | No | Present in typings for parity with other components; not applied in the current implementation. |
Slots
| Slot | Description |
| --- | --- |
| title | Content for the dialog title area. Default text: Downloading. |
Events
All events are DOM CustomEvent instances on hb-downloader.
| Event | detail shape | When it fires |
| --- | --- | --- |
| modalShow | { id: string; show: boolean } | Propagated from the inner hb-dialog whenever its modal visibility changes (including when this component opens or closes the download UI). |
| downloadComplete | { downloaded: boolean; id: string } | After a successful HTTP response (status 2xx), blob URL creation, and save trigger; internal request state is cleared. |
| downloadError | { downloaded: boolean; id: string; error: unknown } | On network/XHR errors, non-2xx status, or thrown errors during setup. downloaded reflects whether a full save had completed. error may be a string (e.g. non-2xx status), an Error, or another thrown value. |
Listen in HTML with the usual oneventname form (e.g. ondownloadcomplete) or addEventListener('downloadComplete', ...).
CSS custom properties
These variables theme the Bulma <progress> bar and the optional percentage label (when the response exposes a known total length).
| Variable | Role |
| --- | --- |
| --bulma-primary | Filled portion of the progress bar. |
| --bulma-border-weak | Track / unfilled background. |
| --bulma-text | Color of the centered percentage text (when total size is known). |
| --bulma-block-spacing | Vertical spacing above the percentage line (the label uses half of this value as top margin). |
CSS ::part
None on this component (styleSetup.parts is empty). Dialog chrome and parts belong to hb-dialog.
Behavior and integration notes
- Method — Single
GETrequest withresponseType: "blob". Progress usesxhr.onprogress(loaded/total). Whiletotalis unknown (0), the UI shows an indeterminate progress bar; whentotalis known, a determinate bar and percentage appear. - File name — If the response includes
Content-Dispositionwith afilename="..."value and the browser can read that header, that name is preferred fordownload. If the header is missing or not exposed, the implementation falls back totargetfilename/ URI inference. For cross-origin responses, the server may need to exposeContent-Disposition(e.g.Access-Control-Expose-Headers) for filename detection to work. - CORS — The origin must be allowed to read the resource and relevant response headers; otherwise the request or filename detection may fail.
- Cleanup — When the dialog closes (
showbecomes false),urianddownloadidare cleared,XMLHttpRequest.abort()is called if needed, anderrorMessageis cleared. Errors are shown as plain text in the dialog body when present. - Headers — Only set headers your endpoint and CORS policy allow; invalid JSON in the
headersattribute is caught and ignored (headers then unset).
Examples
Minimal: URL only
File name is inferred from the path when possible.
<hb-downloader
uri="https://www.w3.org/History/19921103-hypertext/hypertext/WWW/TheProject.html"
></hb-downloader>Explicit file name and correlation id
<hb-downloader
uri="https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
targetfilename="dummy.pdf"
downloadid="demo-pdf"
></hb-downloader>Custom headers (JSON string on the attribute)
Using single quotes around the attribute value avoids escaping inner double quotes.
<hb-downloader
uri="https://httpbin.org/json"
downloadid="json-sample"
headers='{"Accept":"application/json"}'
></hb-downloader>Custom title slot
<hb-downloader uri="https://example.com/report.pdf" targetfilename="report.pdf">
<span slot="title">Saving report…</span>
</hb-downloader>Script listener (vanilla)
const el = document.querySelector('hb-downloader');
el.addEventListener('downloadComplete', (e) => {
console.log('saved', e.detail.downloaded, e.detail.id);
});
el.addEventListener('downloadError', (e) => {
console.error('failed', e.detail.id, e.detail.error);
});
el.addEventListener('modalShow', (e) => {
console.log('dialog', e.detail.show, e.detail.id);
});TypeScript (authoring)
For local typings used when wrapping or typing the element, see types/webcomponent.type.d.ts:
Component—uri, optionalheadersasIHeader(string keys and string values), optionaltargetfilename,downloadid,id,style.Events—downloadError,downloadComplete,modalShowwith thedetailshapes listed above.
Generated consumer typings also appear under types/html-elements.d.ts and types/svelte-elements.d.ts after a web component build.
