Recently, I got a job to download html as an image. Even though it was easy to find related libraries, it was kind of tricky to take a full capture of an element that has a scroll.
I will use my landing page in this post. (GITHUB and DEMO)
First of all, download the packages.
npm i downloadjs html2canvas
or
yarn add downloadjs html2canvas
And if you're using typescript, you must download type package.
npm i -D @types/downloadjs
or
yarn add -D @types/downloadjs
html2canvas: Drawing HTML Element in Canvas
downloadjs: Download Library
Whole HTML
I added a list item in Navbar.
I will implement the download feature on the click event of the list item.
import downloadjs from 'downloadjs';
import html2canvas from 'html2canvas';
// ...
const handleCaptureClick = async () => {
const canvas = await html2canvas(document.body);
const dataURL = canvas.toDataURL('image/png');
downloadjs(dataURL, 'download.png', 'image/png');
};
// ...
<li>
<a href="#" onClick={handleCaptureClick}>
Capture
</a>
</li>
That's it.
Now, click the capture text and you will get that image.
It's very simple.
Specific Element
What if you want to capture a specific element?
There is nothing too difficult, just change the target document.body
to an element you want.
Let's say, we're going to capture Pricing Table section.
[Pricing Table]
// ...
const Prices: React.FC = () => {
// I added the class name 'pricing-table' to get the table element easily.
return (
<div className={cx('prices-section') + ' pricing-table'}>
<SectionTitle>Pricing Table</SectionTitle>
<div className={cx('plans')}>
{plans.map((plan, planIdx) => (
<PlanCard
key={planIdx}
href={plan.href}
title={plan.title}
price={plan.price}
perDate={plan.perDate}
features={plan.features}
/>
))}
</div>
</div>
);
};
[Navbar]
// ...
const handleCaptureClick = async () => {
const pricingTableElmt =
document.querySelector<HTMLElement>('.pricing-table');
if (!pricingTableElmt) return;
const canvas = await html2canvas(pricingTableElmt);
const dataURL = canvas.toDataURL('image/png');
downloadjs(dataURL, 'download.png', 'image/png');
};
// ...
I just replaced document.body
to document.querySelector('pricing-table)
.
It worked well.
Specific Element (Scrolling Capture)
How about capturing an element that has a scroll?
I changed height
of Pricing Table to 200px
.
The scroll appears.
How does it work with the previous code?
The image is cropped.
But this is how it actually works because that's what we can see at this moment.
For capturing a whole element without a scroll, I use some tricks.
const handleCaptureClick = async () => {
const pricingTableElmt =
document.querySelector<HTMLElement>('.pricing-table');
if (!pricingTableElmt) return;
const copiedPricingTableElmt = pricingTableElmt.cloneNode(
true
) as HTMLElement;
copiedPricingTableElmt.style.position = 'fixed';
copiedPricingTableElmt.style.right = '100%';
copiedPricingTableElmt.style.height = 'auto';
document.body.append(copiedPricingTableElmt);
const canvas = await html2canvas(copiedPricingTableElmt);
copiedPricingTableElmt.remove();
const dataURL = canvas.toDataURL('image/png');
downloadjs(dataURL, 'download.png', 'image/png');
};
I cloned the element then set position
to fixed
and right
to 100%
.
Now, you won't be able to see it. Even if it is appended to body
.
Then I adjusted the size. For this case, it's enough to change height
to auto
.
Don't forget to remove the copied element after calling html2canvas
.
Here, you see the final result.
I hope this will be helpful for someone.
Happy Coding!
Top comments (6)
hello , thanks for this . I tried it right away and noticed that the downloaded file excludes image tags within div . that means background images and other photos within the area selected appeared blank on the downloaded file . please explain what i'm doing wrong, thanks
You tried first one? donload body as an image?? I need to know more about situation to know what that was wrong
i tried capturing a particular div within the body . the div contains an image tag with an external source(fetched through the pexels API)
An external source. Okay, I'll make an exmaple and try then I'll tell you. If I don't make the same situation, It would be good that you give me the source code(not your project code) that has same problems.
okay , great
I'm afraid to say that.
html2canvas
seems not working with external images.I found a tric for this. But, it didn't seem working in all cases.
You put the images into a canvas manually, then the images will be included in the download image. However, you should consider yourself like image sizes, styles, which images apprear..
I coded the example and uploaded to Github. I hope you will find something useful in this code.
github.com/hsk-kr/html-2-canvas-ex...
Have a happy coding!