name: lovable-html2canvas-svg-fix
description: Fix SVG elements (QR codes) missing in html2canvas PNG exports on Lovable apps when components remount after state changes
triggers:
- QR code missing in downloaded PNG but visible in preview
- html2canvas capturing blank areas where SVG should be
- layout/theme changes breaking SVG capture in exports
Lovable html2canvas SVG Capture Fix
Problem
In Lovable (or any React app using html2canvas), SVG elements (commonly QR codes) fail to appear in exported PNGs when the parent component has been remounted due to state changes (layout switches, theme toggles, etc.).
Root Cause: html2canvas captures the DOM state, but SVG elements may render differently after React reconciliation, especially when components remount with new keys.
Solution
Convert the SVG to a data URL image BEFORE calling html2canvas. Inject this JavaScript into the page before export:
`javascript
async function fixSVGForCapture(selector) {
const container = document.querySelector(selector);
if (!container) return;
const svg = container.querySelector('svg');
if (!svg) return;
// Get SVG dimensions
const width = parseInt(svg.getAttribute('width')) || 110;
const height = parseInt(svg.getAttribute('height')) || 110;
// Create canvas
const canvas = document.createElement('canvas');
canvas.width = width * 2; // 2x for quality
canvas.height = height * 2;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Serialize SVG and convert to image
const svgData = new XMLSerializer().serializeToString(svg);
const blob = new Blob([svgData], {type: 'image/svg+xml'});
const url = URL.createObjectURL(blob);
await new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
URL.revokeObjectURL(url);
resolve();
};
img.onerror = reject;
img.src = url;
});
// Replace SVG with img
const imgEl = document.createElement('img');
imgEl.src = canvas.toDataURL('image/png');
imgEl.style.cssText = 'width:100%;height:100%;display:block;';
container.innerHTML = '';
container.appendChild(imgEl);
}
// Usage before html2canvas:
await fixSVGForCapture('[data-qr-target="true"]');
// Now call html2canvas...
`
When to Use
- - QR code (or any SVG) missing in html2canvas export
- - Component remounts on state change (layout, theme, etc.)
- - Works in preview but missing in downloaded PNG
- - html2canvas captures blank areas where SVG should be
- - Selector:
[data-qr-target="true"] - - QR code is SVG, not canvas or img tag
- - Layout changes (Clássico/Central/Lado a Lado) cause React to remount QR component
- -
[data-qr-target="true"]selector IS present in DOM during normal page inspection - - Browser console queries via automation (Browserbase/Playwright) may return 0 results even when elements exist - this is a timing/context issue with automated browser sessions
- - Visual inspection via screenshot is more reliable than DOM queries in these sessions
- - The QR code container uses React key-based remounting:
key={qr-${config.layout}-${size}-${referralLink}} - - Critical: Layout changes cause React to remount the QR component, so html2canvas capture must wait 200ms after any layout/state change
- - Image analysis confirmed: QR code text "Escaneie o QR Code" visible but NO square pattern in its place
- - Layout "Central" with default colors tested
- - Banner exported notification appears, but PNG has blank area where QR should be
Lovable-specific context
Used for: rocha-afiliados.lovable.app banner creator
Verification
After fix, screenshot the preview area directly (browser.screenshot() or page.screenshot()) rather than relying on html2canvas for SVG-heavy components.
Debugging Notes (from rocha-afiliados session)
Alternative: Local Puppeteer Script
If the Lovable fix cannot be applied, use a local Node.js script with Puppeteer:
`javascript
// key steps:
await page.waitForSelector('[data-qr-target="true"]');
await page.evaluate(() => {
// Convert SVG to canvas in-page
const svg = document.querySelector('[data-qr-target="true"] svg');
// ... SVG to canvas conversion ...
});
await page.screenshot({ type: 'png', clip: {...} }); // Use Puppeteer screenshot, NOT html2canvas
`