I am using react-pdf to generate PDF files directly on the client to avoid unnecessary network requests. I am using @react-pdf/dom and the PDFs are rendered successfully in an iframe. However, I want my users to be able to download the PDF and I want to be able to specify the name of the file when it is downloaded. I couldn't figure out how to setup the PDF such that when they click the download link in the iframe, the save dialog uses a defined filename. Am I missing something?
I was able to get my desired output by bypassing the iframe rendering and instead using the blob here and used it to trigger an a tag with src and download properties set. This does the trick:
pdf(this.container)
.toBlob()
.then(blob => {
const data = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = data;
link.download = this.props.title || "output.pdf";
link.click();
setTimeout(() => {
// For Firefox it is necessary to delay revoking the ObjectURL
URL.revokeObjectURL(data)
}, 100)
});
I'm hoping to contribute this feature to the library, as I think others would find it useful to have the option to access the PDF blob directly so they can perform this type of download.
My thought is that @react-pdf/dom might be better of exposing a DocumentViewer object (which is what the current Document element is in my mind) and maybe a DocumentDownloader that works as I described above. To me, it's a bit surprising that the Document element is actually an iframe. It might make more sense for it to be a Blob that represents the generated PDF file.
Thoughts?
Hi!
I agree that the dom-bindings are a bit primitives and don't fit most use cases.
These past days I was working on react-pdf landing page and I had a similar problem myself. I ended up doing something like you did, and using the homonymous react-pdf library for rendering the document. You can see it in action here.
I thought that maybe the new dom bindings can be something similar as I implement there. I truly don't want/have time to implement a Viewer myself (out of scope of this project for now), but that one works great I think. The dom bindings can also export components such as PageNavigation and Download to make all those features easy to use. Can be something like this:
import { Text } from '@react-pdf/core';
import { Viewer, Document, PageNavigation, Download } from '@react-pdf/dom';
export const = () => (
<Viewer>
<Document>
<Text>
Lorem ipsum
</Text>
</Document>
<div className="whatever">
<PageNavigation leftArrow={SomeComponent} rightArrow={SomeOtherComponent} />
<Download>
<button>Download document</button>
</Download>
</div>
</Viewer>
);
We can make use of React context API to wire all those component internally, so they can be easy to use, and yet extensible to each user's needs (by accepting className and styles props, etc).
What do you think?
Btw, You can find the page code in here. It's also open source 馃槃
Cool, thanks for sharing that code! In my case, I would actually just want to have access to the URL of the blob, so the API you proposed might not provide what I would need.
For now, I might just copy what you did with the core primitives to generate the URL and work with it directly.
As someone just starting out with this library who's encountering the same issue, I wasn't really able to understand how to solve it from this thread. Maybe this could be kept open until there's official support for filename configuration?
Thanks @SachaG .
Going to test this with the new version, and add docs.
After that I'll close it
Most helpful comment
Thanks @SachaG .
Going to test this with the new version, and add docs.
After that I'll close it