Download Progress Button
A free download progress button for Next.js and React with determinate, cancel, success and retry states.
Determinate transfer
Start the download, or cancel it midway to reveal the retry state.
Customise
Code
<BtnDownloadProgress />Download Progress Button is a free button component for Next.js and React, styled with Tailwind, that presents a determinate file transfer across idle, downloading, success and error states. Pass a controlled percentage and status, then connect the primary and optional cancel actions to your own download logic.
The fixed footprint prevents layout shift while Motion swaps one icon and one label at a time, scales the progress fill from the left, draws the success check and nudges the error state once. A native cancel button remains independently keyboard reachable, the active percentage is exposed as a progressbar, success and error are politely announced, and reduced motion makes every state update instant and static.
Install
Add the @te registry to your components.json once:
{
"registries": {
"@te": "https://templateempire.io/r/{name}.json"
}
}Then install the component:
npx shadcn@latest add @te/btn-download-progressUsage
"use client";
import { useState } from "react";
import { BtnDownloadProgress } from "@/components/btn-download-progress";
type DownloadStatus = "idle" | "downloading" | "success" | "error";
export default function DownloadButton() {
const [status, setStatus] = useState<DownloadStatus>("idle");
const [progress, setProgress] = useState(0);
return (
<BtnDownloadProgress
progress={progress}
status={status}
onAction={() => {
setProgress(0);
setStatus("downloading");
}}
onCancel={() => setStatus("error")}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| progress | number | 0 | Determinate value clamped to 0 through 100. |
| status | "idle" | "downloading" | "success" | "error" | "idle" | Controlled visual and semantic state. |
| label | string | "Download" | Idle visible label. |
| downloadingLabel | string | "Downloading" | Active visible label with the percentage appended. |
| successLabel | string | "Downloaded" | Completed visible label and polite announcement. |
| errorLabel | string | "Try again" | Error visible label and polite announcement. |
| width | number | 184 | CSS pixel width clamped to 144 through 280. |
| height | number | 48 | CSS pixel height clamped to 40 through 64. |
| progressHeight | number | 3 | Track height in CSS pixels, clamped to 2 through 8. |
| iconTravel | number | 10 | Vertical icon travel in CSS pixels, clamped to 0 through 18. |
| settleDuration | number | 420 | Success draw and error settle time in milliseconds, clamped to 180 through 900. |
| disabled | boolean | false | Uses native button disabled behaviour for both actions. |
| onAction | () => void | undefined | Starts an idle download or retries an error. |
| onCancel | () => void | undefined | Invoked from the independently focusable active cancel button. |
| className | string | undefined | Additional classes merged onto the fixed-size root group. |
Customisation
Download Progress Button exposes three Tier 3 colour tokens. The fill token paints determinate progress and the success icon, the track token paints the inactive rail, and the error token paints the retry state. Override them on any ancestor while geometry and timing remain available through the component props:
<div
style={{
"--download-progress-fill": "var(--primary)",
"--download-progress-track": "var(--muted)",
"--download-progress-error": "var(--destructive)",
}}
>
<BtnDownloadProgress
progress={progress}
status={status}
width={208}
progressHeight={4}
onAction={startDownload}
onCancel={cancelDownload}
/>
</div>Frequently asked questions
- Is Download Progress Button free for commercial use?
- Yes. Download Progress Button is MIT licensed, so you can use it in personal and commercial projects without attribution.
- Is the progress button accessible and reduced-motion safe?
- Yes. The primary and cancel actions are separate native buttons with visible focus rings, downloading exposes a named determinate progressbar, and a polite live region announces success or error once. Motion changes only transforms and opacity inside a fixed footprint. With reduced motion enabled, the percentage and states remain fully usable but every swap, icon movement, path draw and error nudge becomes instant.
- How do I customise the progress track and timing?
- Set width, height and progressHeight for the fixed geometry, iconTravel for the vertical icon movement, and settleDuration for the success or error beat. Retint the fill, track and error accent with the three component tokens, which default to your primary, muted and destructive semantic colours.