# Render QR codes in the browser

Browser applications can render a QR code as an SVG string, a PNG-backed Image element, or a
Canvas element. Choose the output for what the page needs to do next, then insert or compose the
returned value with standard browser APIs.

## Choose a browser output

| Choose | Package              | Return value        | Best fit                                                   |
| ------ | -------------------- | ------------------- | ---------------------------------------------------------- |
| SVG    | `@qrcodesdk/core`    | `string`            | Scalable inline markup and the recommended browser default |
| Image  | `@qrcodesdk/browser` | `HTMLImageElement`  | A familiar, accessible DOM image backed by PNG data        |
| Canvas | `@qrcodesdk/browser` | `HTMLCanvasElement` | Drawing, compositing, pixel access, or manual PNG export   |

Start with SVG unless the next browser API specifically needs an Image or Canvas element. SVG stays
sharp when resized and does not require Canvas support. Image and Canvas output require both
`@qrcodesdk/core` and `@qrcodesdk/browser`.

:::note[Client-side rendering]
Create Image and Canvas renderers only after browser DOM APIs are available. In a server-rendered
application, run them after hydration or use the runtime-neutral SVG renderer on the server.
:::

## SVG string

`QRCodeSVGRenderer` returns complete SVG markup. It is not a DOM node, so insert it into an existing
element or pass it to the browser-side template system that owns the page.

### Insert it into the DOM

Render into a container when the SVG should participate in the page as inline markup:

```ts
import {QRCodeSVGRenderer, qrcode} from '@qrcodesdk/core';

const svg = qrcode('https://qrcodesdk.dev').render(
  QRCodeSVGRenderer({
    ariaLabel: 'Scan to open qrcodesdk.dev',
  }),
);

const container = document.querySelector('#qrcode');

if (container) {
  container.innerHTML = svg;
}
```

```html
<div id="qrcode"></div>
```

Only insert the string as HTML when the renderer and its options are inside your application's
trust boundary.

### Include it in browser-generated markup

The returned string can be interpolated into HTML generated by a browser-side template:

```ts
import {QRCodeSVGRenderer, qrcode} from '@qrcodesdk/core';

const svg = qrcode('https://qrcodesdk.dev').render(
  QRCodeSVGRenderer({
    ariaLabel: 'Scan to open qrcodesdk.dev',
  }),
);

const html = `
  <section>
    <h2>Scan this QR code</h2>
    ${svg}
  </section>
`;
```

Apply layout styles to the inserted root SVG through its container:

```css
#qrcode > svg {
  display: block;
  width: min(100%, 20rem);
  height: auto;
}
```

## Image element

`QRCodeImageRenderer` synchronously returns a new `HTMLImageElement` whose `src` contains the
rendered PNG as a data URL. Use it when the QR code should behave like an ordinary image in the DOM.

### Insert and style it

The returned value is already an `HTMLImageElement`, so it can be appended and styled like any
other image:

```ts
import {QRCodeImageRenderer} from '@qrcodesdk/browser';
import {qrcode} from '@qrcodesdk/core';

const image = qrcode('https://qrcodesdk.dev').render(
  QRCodeImageRenderer({
    alt: 'QR code for qrcodesdk.dev',
    ariaLabel: 'Scan to open qrcodesdk.dev',
    title: 'QR code for qrcodesdk.dev',
  }),
);

image.className = 'qrcode';
document.querySelector('#qrcode')?.append(image);
```

```html
<div id="qrcode"></div>
```

```css
.qrcode {
  display: block;
  width: min(100%, 20rem);
  height: auto;
}
```

### Use the PNG data URL

Read `src` when another browser API needs the encoded PNG rather than the element:

```ts
import {QRCodeImageRenderer} from '@qrcodesdk/browser';
import {qrcode} from '@qrcodesdk/core';

const image = qrcode('https://qrcodesdk.dev').render(QRCodeImageRenderer());
const response = await fetch(image.src);
const png = await response.blob();

await navigator.clipboard.write([
  new ClipboardItem({
    'image/png': png,
  }),
]);
```

The Clipboard API requires a secure context and may require a user gesture or permission.

## Canvas element

`QRCodeCanvasRenderer` synchronously returns a new `HTMLCanvasElement`. Use Canvas when code needs
to draw onto the output, combine it with other graphics, inspect pixels, or export it manually.

### Insert it into the DOM

Give the Canvas its own accessible name, then append it wherever the QR code should appear:

```ts
import {QRCodeCanvasRenderer} from '@qrcodesdk/browser';
import {qrcode} from '@qrcodesdk/core';

const canvas = qrcode('https://qrcodesdk.dev').render(QRCodeCanvasRenderer({size: 8, margin: 4}));

canvas.setAttribute('role', 'img');
canvas.setAttribute('aria-label', 'Scan to open qrcodesdk.dev');
document.querySelector('#qrcode')?.append(canvas);
```

```html
<div id="qrcode"></div>
```

### Draw it into another Canvas

Use the QR Canvas as a source for a larger composition:

```ts
import {QRCodeCanvasRenderer} from '@qrcodesdk/browser';
import {qrcode} from '@qrcodesdk/core';

const qrCanvas = qrcode('https://qrcodesdk.dev').render(QRCodeCanvasRenderer());
const target = document.querySelector<HTMLCanvasElement>('#target');
const context = target?.getContext('2d');

if (target && context) {
  target.width = qrCanvas.width;
  target.height = qrCanvas.height;
  context.drawImage(qrCanvas, 0, 0);
}
```

## Replace a rendered QR code

Each render creates a new string or element. When the payload changes, render again and replace the
old output so the container does not accumulate QR codes:

```ts
import {QRCodeImageRenderer} from '@qrcodesdk/browser';
import {qrcode} from '@qrcodesdk/core';

const container = document.querySelector('#qrcode');

export function updateQRCode(data: string) {
  const image = qrcode(data).render(
    QRCodeImageRenderer({alt: '', ariaLabel: `Scan to open ${data}`}),
  );

  container?.replaceChildren(image);
}
```

If application state changes frequently, avoid recreating output for unrelated updates. Framework
users can instead use the React, Vue, Svelte, or Angular components, which integrate rendering with
their normal component lifecycle.

## Keep browser output reliable

- Keep the default four-module margin clear of nearby text, borders, and other UI.
- Give meaningful SVG, Image or Canvas output an accessible label.
- Use CSS to shrink output responsively, but do not enlarge Image or Canvas output beyond its
  rendered pixel dimensions. Increase the renderer's `size` when more raster resolution is needed.
- Scan-test the final page at its smallest supported viewport and after any CSS transforms, browser
  zoom, screenshots, or image compression.

## Result and next step

The QR code now uses the browser output that matches its next operation and is mounted with normal
DOM APIs. Follow [Customize appearance](/guides/customize/) for shared visual options,
[Add a center image](/guides/center-images/) for prepared image sources, or
[Download or save](/guides/download-or-save/) to turn the output into a file.
