You cannot. There is no cancel button, no keyboard shortcut and no abort path — the page has exactly one button, and it is Convert another. Once a file is handed over, it runs to completion: as little as 164 ms for a phone-sized photo, 5–7 seconds for a 12-megapixel one, 10–15 seconds for a 27-megapixel one. The only exit is to reload the page or close the tab, and that throws away everything done so far.
Short answer: no. I tried seven different ways to stop a conversion that had already begun — clicking the upload area, pressing Escape, clicking Convert another, changing the quality setting, handing over a second file, clicking the spinner itself, and clicking a link to leave the page. Six of them did nothing at all: the conversion finished anyway and produced the same 3,177,680-byte file every time. The seventh left the page, which is the only thing that genuinely stops the work.
There is nothing to click. The live page I measured today is 14,457 bytes and contains one <button>, eighteen links, one <select> and one file input. The word "cancel" appears zero times in the visible text, and AbortController, abort( and terminate appear zero times in the page source. The spinner is a plain <div> reading "Converting…" with no role, no aria-live and no click handler.
Reloading is the only cancel, and it is a real loss. On a 12-megapixel file whose conversions were taking a median of 5,518 ms, reloading a quarter of the way in discarded 1,426 ms of work; halfway in, 2,783 ms; three quarters in, 4,209 ms. Nothing survives — no partial result, no message, no error.
I loaded the converter and inventoried every interactive thing on it. This is the whole list:
| Element | What it is | Can it stop a conversion? |
|---|---|---|
#again (the only button) | "Convert another" | No — it hides the result area and clears the file input |
#drop (upload area) | A clickable region, 714 × 180 px | No — it opens the file picker |
#q (quality) | A select with three options | No — it is read when the file is handed over |
#finput (file input) | Hidden, enabled, not multiple | No — it starts conversions |
#busy (spinner) | A div, text "Converting…" | No — no role, no handler, no aria-live |
| 18 links | Navigation and guide links | Only by leaving the page |
I also searched the page for the machinery a cancel button would need. In the 14,457 bytes of live HTML: AbortController 0, abort( 0, cancel 0, terminate 0, setTimeout 0, setInterval 0, six addEventListener calls, one .then( and one .catch(. In the decoder itself, the 2,999,737-character heic-to.js: AbortController 0, abort( 0, cancel 0, terminate 1, setTimeout 3. On screen there are zero <progress> elements, zero <dialog> elements and zero aria-live regions, and the 4,064 characters of visible text contain no instance of "cancel", "stop", "abort" or "interrupt".
That last point matters as much as the missing button: there is no progress indicator either. You are not told how far along a conversion is, only that it is running.
I started a 12-megapixel conversion (11,084,868 bytes) and took a snapshot of every control 1,209 ms in, while it was still working:
| Element | State mid-conversion |
|---|---|
| Spinner | visible (block), pointer events auto, plain cursor — clickable, but nothing happens |
| Upload area | visible, pointer events auto, cursor pointer, no disabled attribute |
| Quality menu | visible and enabled — not greyed out, not disabled |
| File input | hidden, enabled |
| Convert another | computed as inline-flex, but its container is hidden, so it is not on screen |
| Result area / error area | both hidden |
Nothing is locked during a conversion. The upload area still invites a click, the quality menu still looks usable, and neither does anything to the work in flight — which is exactly why this feels like it ought to be cancellable. That conversion went on to finish normally at 3,177,680 bytes after 14,257 ms.
Each row is a separate run on a freshly reloaded page, using the same 12-megapixel file. The intervention was applied about 1.5 seconds in, while the spinner was still visible. Every conversion that was allowed to finish produced the same file: 3,177,680 bytes, 4032×3024, identical SHA-256.
| What I did | When | Did it stop? | What happened instead |
|---|---|---|---|
| Nothing (control) | — | — | finished in 8,348 ms |
| Clicked the upload area | 1,527 ms | no | the file picker opened; spinner stayed visible; finished in 6,113 ms |
| Pressed Escape | 1,572 ms | no | spinner stayed visible; finished in 8,075 ms |
| Clicked Convert another | 1,519 ms | no | result area stayed hidden, info line stayed empty; finished in 6,412 ms |
| Changed quality 85% → 75% | 1,544 ms | no | the converter still used 0.85 and produced the same file; finished in 6,123 ms |
| Handed over a second file | 1,534 ms | no | two conversions ran; the first still finished in 8,889 ms |
| Clicked the spinner itself | 1,531 ms | no | finished in 6,100 ms |
| Clicked a footer link to leave | 1,572 ms | yes | the page navigated 142 ms after the click |
Two of those deserve a note. Handing over a second file does not replace the first — it starts a second, parallel piece of work, which I measured separately in dropping a second photo in mid-conversion. And changing the quality setting does not stop or restart anything, because the setting is read once, at the moment the file is handed over, as I measured in changing quality midway.
Leaving the page by clicking a link is the one action that works, and it works quickly: the navigation began 142 ms after my click, against 373 ms for the same link clicked on an idle page. The main thread is not blocked while a conversion runs, so you can always walk away — you just cannot stop the work and keep the page.
I first measured the file's normal cost — three uninterrupted conversions of the same 12-megapixel HEIC took 12,249, 5,518 and 4,374 ms, a median of 5,518 ms. Then I started three more and reloaded the page at a quarter, a half and three quarters of that median.
| Reload issued at | Work discarded | Page ready again after | State after reload |
|---|---|---|---|
| 25% (1,380 ms target) | 1,426 ms | 208 ms | clean |
| 50% (2,759 ms target) | 2,783 ms | 235 ms | clean |
| 75% (4,139 ms target) | 4,209 ms | 227 ms | clean |
| idle page (control) | — | 249 ms | clean |
"Clean" means the same four things every time: spinner hidden, result area hidden, error area hidden, info line empty, download link empty, file input holding zero files, and zero console entries. There is no partial JPG and no "you cancelled something" message. That matches what I found in reloading or switching away mid-conversion: the work is simply gone.
The reload itself is cheap and indifferent to how much work it is destroying: the page came back in 208, 235 and 227 ms, against 249 ms for a reload of an idle page. Abandoning a conversion costs no more than reloading a page that was doing nothing.
Before the file is handed over, you are still in charge. I clicked the upload area on a fresh page and let the file picker open without choosing anything: three seconds later, zero conversions had started and the spinner was not showing. So dismissing the picker really is a cancel — it is just a cancel of a conversion that never began.
It is also harmless to an existing result. After one photo had finished converting (38,078 bytes, 700×476), I opened the picker again and ignored it; three seconds later the result area was still on screen and the info line was unchanged. Nothing was destroyed by opening and dismissing the dialog in my test.
A caveat on how I measured this: rather than pressing Cancel in a real operating-system dialog, I had Chrome intercept the picker and then never answered it. The effect on the page should be the same — no file arrives, so nothing starts — but I did not click a real Cancel button.
Whether any of this matters depends on the file. These are three consecutive conversions each, at the default quality, of four different sizes. The first conversion after a page load carries the decoder warm-up cost, which is why the first number in each row is the largest.
| Source | HEIC in | JPG out | Three runs |
|---|---|---|---|
| 700 × 476 (phone photo) | 41,465 B | 38,078 B | 778 / 196 / 164 ms |
| 2000 × 1500 | 2,768,977 B | 795,543 B | 2,030 / 1,242 / 1,317 ms |
| 4032 × 3024 (12 MP) | 11,084,868 B | 3,177,680 B | 7,062 / 5,317 / 6,036 ms |
| 6000 × 4500 (27 MP) | 24,470,938 B | 7,013,308 B | 14,956 / 12,945 / 10,207 ms |
At the top of that table the whole question is academic — 164 ms is over before you can reach for anything. At the bottom it is not: a 27-megapixel file holds the page for ten to fifteen seconds with no way to call it off. For reference, the largest file I have pushed through this converter is 108 megapixels, which took 75,996 ms, as measured in how large a HEIC it can take.
This part is a probe rather than something you can do as a visitor, so treat it as evidence about the page rather than advice. The decoder runs in one worker. I started a 12-megapixel conversion, killed that worker 1,529 ms in, and then watched the page for almost 22 seconds.
The spinner stayed visible the whole time, sampled every two seconds. The result area never appeared, the error area never appeared, no console entry was written, and the page still answered every query I sent it. Nothing gave up, nothing timed out, nothing explained itself. The page has no watchdog: if the work disappears without reporting back, it waits forever.
That is the flip side of having no cancel button. A cancel control needs the same plumbing as an error path, and neither exists here — the only two outcomes the page knows how to draw are "Converting…" and "done".
No. I counted one <button> on the page and it is "Convert another". The words "cancel", "stop" and "abort" do not appear anywhere in the 4,064 characters of visible text, and AbortController does not appear in the page source or in the decoder.
No. I pressed Escape 1,572 ms into a 12-megapixel conversion and it finished 8,075 ms in, producing the same 3,177,680-byte file. There is no keyboard route to the upload area at all, which I measured in the keyboard-only test.
Both abandon the work completely. I measured reloading at three points in this article; closing the tab behaves the same way and also produces no warning, as I found in the tests on leaving the page.
I can only describe what is there, not why. The conversion is a single call that hands the file to the decoder and waits for one result, with no mechanism in the page or in the decoder to interrupt it, and no error path other than the generic failure message. Adding a real cancel would mean changing both.
The output does not change — I have measured identical bytes across browsers and device pixel ratios in the browser support tests. The durations in this article are from one desktop machine running Chrome 154, and a slower device will stretch every one of them, as measured in the slow-CPU tests.
Try it: open the converter and drop in one photo. Watch the spinner — that is the whole interface until it finishes.
First published: 13 October 2026