You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

47 lines
1.3 KiB

'use client';
import { useEffect, useRef } from 'react';
interface Props {
data: string;
size?: number;
}
/**
* Renders a styled QR code for `data`. `qr-code-styling` touches the DOM, so it
* is imported lazily inside the effect to stay clear of SSR.
*/
export function QrCode({ data, size = 240 }: Props) {
const containerRef = useRef<HTMLDivElement>(null);
// biome-ignore lint/suspicious/noExplicitAny: qr-code-styling instance type loaded lazily
const instanceRef = useRef<any>(null);
// biome-ignore lint/correctness/useExhaustiveDependencies: initial data is read once here; later changes go through update() in the next effect
useEffect(() => {
let cancelled = false;
(async () => {
const { default: QRCodeStyling } = await import('qr-code-styling');
if (cancelled) return;
instanceRef.current = new QRCodeStyling({
width: size,
height: size,
type: 'svg',
data,
dotsOptions: { type: 'rounded' },
});
if (containerRef.current) {
containerRef.current.replaceChildren();
instanceRef.current.append(containerRef.current);
}
})();
return () => {
cancelled = true;
};
}, [size]);
useEffect(() => {
instanceRef.current?.update({ data });
}, [data]);
return <div ref={containerRef} role="img" aria-label="QR code" />;
}