html-to-image Reference

Capture DOM elements as PNG, JPEG, SVG, or Blob outputs for dashboards, cards, certificates, and shareable graphics.

Imports and setup

import { Download } from "lucide-react";

export default function App() {
  const cardRef = React.useRef<HTMLDivElement>(null);
  const { download } = useDownload();
  const [exporting, setExporting] = React.useState(false);

  const handleExport = async () => {
    if (!cardRef.current) return;
    setExporting(true);
    try {
      const dataUrl = await toPng(cardRef.current, {
        pixelRatio: 2,
        backgroundColor: "#ffffff",
      });
      download(dataUrl, "summary.png");
    } finally {
      setExporting(false);
    }
  };

  return (
    <div>
      <div ref={cardRef}>
        <div>
          <h3>Weekly Summary</h3>
        </div>
        <div>
          <p className="text-2xl font-bold">127 tasks completed</p>
          <p className="text-muted-foreground">Up 12% from last week</p>
        </div>
      </div>
      <button onClick={handleExport} disabled={exporting}>
        {exporting ? <span className="inline-block h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" /> : <Download className="h-4 w-4" />}
        Export as PNG
      </button>
    </div>
  );
}

JPEG and Blob exports

Use JPEG for photo-heavy content and set a white background because JPEG does not preserve transparency.

const dataUrl = await toJpeg(ref.current, {
  quality: 0.92,
  backgroundColor: "#ffffff",
});
download(dataUrl, "export.jpeg");

Use toBlob() for a memory-efficient download path, especially for large captures.

const blob = await toBlob(ref.current, { pixelRatio: 2 });
if (blob) {
  download(blob, "capture.png");
}

Filtering controls

Exclude buttons, toolbars, and other interactive controls with the filter option and a data-* attribute.

const dataUrl = await toPng(ref.current, {
  filter: (node) => {
    if (node instanceof HTMLElement && node.dataset.excludeExport) {
      return false;
    }
    return true;
  },
});
<div ref={ref} className="rounded-lg bg-card p-4">
  <h2 className="text-xl font-bold">My Report</h2>
  <p>This content will be exported.</p>
  <div data-exclude-export="true">
    <button onClick={handleExport}>Export</button>
  </div>
</div>

Best practices

Use pixelRatio: 2 for crisp exports, set backgroundColor for transparent or JPEG exports, prefer toBlob() with useDownload for large captures, filter out controls with data-* attributes, show a loading state while capturing, and wrap the target in a container with explicit background and padding so the exported image looks complete.