@svelte-put/qr GitHub

render QR as img or svg, optionally with logo

@svelte-put/qr @svelte-put/qr @svelte-put/qr @svelte-put/qr changelog

Installation

npm install --save-dev @svelte-put/qr
pnpm add -D @svelte-put/qr
yarn add -D @svelte-put/qr

Kudos

This package is made possible by qrcode-generator and heavily inspired by bitjson/qr-code. Please check out their work for more information.

SVG

@svelte-put/qr allows rendering QR as svg. Depending on the scenario, you may find certain strategy more convenient than others.

  • action: quick and minimal, enough if you do not care about server side rendering (SSR) or prerendering, and is especially helpful if you need access to the SVGElement (for styling or event handling),
  • component: good if you prefer having component abstraction, also applicable to SSR and prerendering. However, you lose direct access to the SVGElement,
  • component with custom default slot: good if you want a component and also need access to the SVGElement.
<script>
  import { qr } from '@svelte-put/qr/svg';
</script>

<svg
  use:qr={{
    data: 'https://svelte-put.vnphanquang.com/docs/qr',
    logo: 'https://svelte-put.vnphanquang.com/images/svelte-put-logo.svg',
    shape: 'circle',
  }}
/>
<script>
  import QR from '@svelte-put/qr/svg/QR.svelte';
</script>

<QR
  data="https://svelte-put.vnphanquang.com/docs/qr"
  moduleFill="violet"
  anchorOuterFill="red"
  anchorInnerFill="violet"
/>
<script>
  import QR from '@svelte-put/qr/svg/QR.svelte';
</script>

<QR
  data="https://svelte.dev"
  logo="https://raw.githubusercontent.com/sveltejs/branding/master/svelte-logo.svg"
  logoRatio={107 / 128}
  shape="square"
	anchorInnerFill="tomato"
	anchorOuterFill="tomato"
	moduleFill="tomato"
	margin={4}
  let:attributes
  let:innerHTML
>
  <svg {...attributes} color="gray">
    <!-- eslint-disable-next-line svelte/no-at-html-tags -->
    {@html innerHTML}
  </svg>
</QR>

Note the imports from subpackage @svelte-put/qr/svg in the examples above.

SVG Headless Helpers

@svelte-put/qr exports two top-level helpers, createQrSvgString and createQrSvgDataUrl, that allow you to create QR code programmatically as string or Base64 SVG Data URL, respectively. The aforementioned helpers works in both browser and server.

<script>
	import { createQrSvgString, createQrSvgDataUrl } from '@svelte-put/qr';

	const config = { data: 'https://svelte.dev' }

	const dataURL = createQrSvgDataUrl(config);
	const svgString = createQrSvgString(config);
</script>

<div class="flex items-center gap-2 flex-col">
	{@html svgString}
	<a class="c-btn" href={dataURL} download="qr.svg">Download QR as SVG</a>
</div>

Image

@svelte-put/qr also allows rendering QR as img. The available strategies are similar to those found in the previous section.

  • action: quick and minimal, only rendered at runtime in browser,
  • component: useful for SSR and prerendering,
  • component with custom default slot: useful if you need to use component and have access to HTMLImageElement.
qr

Since v1.2.0, @svelte-put/qr renders a base64 PNG image for img in the browser using the Canvas API. On the server (i.e during prerendering and SSR), however, it will render a base64 SVG instead, since canvas is not available there.

The rendered PNG has the default size of 1000x1000, it is recommended that you specify width and height explicitly.

<script>
  import { qr } from '@svelte-put/qr/img';
</script>

<img
  use:qr={{
    data: 'https://svelte-put.vnphanquang.com/docs/qr',
    logo: 'https://svelte-put.vnphanquang.com/images/svelte-put-logo.svg',
    shape: 'circle',
    anchorInnerFill: 'gray',
    anchorOuterFill: 'gray',
    moduleFill: 'gray',
    width: 500,
    height: 500,
  }}
  alt="qr"
/>
<script>
  import QR from '@svelte-put/qr/img/QR.svelte';
</script>

<QR
  data="https://svelte-put.vnphanquang.com/docs/qr"
  moduleFill="violet"
  anchorOuterFill="red"
  anchorInnerFill="violet"
	width="500"
	height="500"
/>
<script>
  import QR from '@svelte-put/qr/img/QR.svelte';
</script>

<QR
  data="https://svelte.dev"
  logo="https://raw.githubusercontent.com/sveltejs/branding/master/svelte-logo.svg"
  logoRatio={107 / 128}
  shape="square"
	anchorInnerFill="tomato"
	anchorOuterFill="tomato"
	moduleFill="tomato"
	margin={4}
	width="500"
	height="500"
  let:src
>
  <img {src} alt="qr" />
</QR>

Note the imports from subpackage @svelte-put/qr/img in the examples above.

Background Fill

In addition to moduleFill, anchorOuterFill, and anchorInnerFill, listed in Common Configuration, img strategies accept a backgroundFill option to specify the background of the QR code.

https://svelte-put.vnphanquang.com/docs/qr
<script>
  import QR from '@svelte-put/qr/img/QR.svelte';
</script>

<QR
  data="https://svelte-put.vnphanquang.com/docs/qr"
  anchorOuterFill="blue"
  moduleFill="green"
  anchorInnerFill="blue"
	backgroundFill="lightblue"
	width="168"
	height="168"
/>

PNG Headless Helper

In case you want to create a base64 PNG data URL QR code programmatically, @svelte-put/qr exports a top-level helper named createQrPngDataUrl for your convenience. This is helpful, for example, if you want to generate a downloadable link.

<script>
	import { createQrPngDataUrl } from '@svelte-put/qr';
	import { onMount } from 'svelte';

	const config = {
		data: 'https://svelte.dev',
		width: 500,
		height: 500,
		backgroundFill: '#fff',
	}

	let src = '';
	onMount(async () => {
		src = await createQrPngDataUrl(config);
	});
</script>

<div class="flex items-center gap-2 flex-col">
	<img {src} width="180" height="180" alt="a qr code" />
	<a class="c-btn" href={src} download="qr.png">Download QR as PNG</a>
</div>

Note that createQrPngDataUrl requires the Canvas API and only works in browser.

Common Configuration

Rendering strategies exported by @svelte-put/qr/*, whether it’s svg or img, component or action, all share the following configuration interface.

/**
 * instructions to render a QR
 * @public
 */
export type QRConfig = {
	/** the data to encode in QR, typically an URL */
	data: string;
	/**
	 * the quite zone along the edges of QR
	 */
	margin?: number;
	/**
	 * determine what shape to render the elements
	 *
	 * - `square` (default): each module or anchor is a sharp-edged square
	 * - `circle`: each module is a circle, each anchor is a round-edged square
	 */
	shape?: 'square' | 'circle';
	/**
	 * logo to render in the middle of QR
	 */
	logo?: string;
	/** width : height */
	logoRatio?: number;

	/* styling */
	/** fill for each module */
	moduleFill?: string;
	/** fill for the outer ring of each anchor (big positioning square at the corners) */
	anchorOuterFill?: string;
	/** fill for the inner square of each anchor */
	anchorInnerFill?: string;
	/**
	 * Type number (1 ~ 40), or 0 for auto detection,
	 * passed as parameter to {@link https://github.com/kazuhikoarase/qrcode-generator | qrcode-generator},
   * default to 0,
	 */
	typeNumber?: Parameters<typeof QR>[0];
	/**
	 * Error correction level ('L', 'M', 'Q', 'H'),
	 * passed as parameter to {@link https://github.com/kazuhikoarase/qrcode-generator | qrcode-generator},
   * default to H,
	 */
	errorCorrectionLevel?: Parameters<typeof QR>[1];
};

Events

All rendering strategies share a qr:init CustomEvent that fires when the rendering is completed. Its event.detail is the element itself (SVGElement or HTMLImageElement).

@svelte-put/qr/img/QR.svelte might also fire another CustomEvent named qr:logofetch, the event.detail of which is the base64 encoded logo. This only happens if you specify the logo prop / option as /http*./, which has to be fetched manually to be compatible for conversion to base64 svg.

<script lang="ts">
  import { qr as imgQR } from '@svelte-put/qr/img';
  import ImgQR from '@svelte-put/qr/img/QR.svelte';
  import { qr as svgQR } from '@svelte-put/qr/svg';
  import SvgQR from '@svelte-put/qr/svg/QR.svelte';

  const data = 'https://svelte-put.vnphanquang.com';
</script>

<svg use:svgQR={{ data }} on:qr:init={(e) => console.log(e.detail /** SVGElement */)} />

<SvgQR {data} on:qr:init={(e) => console.log(e.detail /** SVGElement */)} />

<img use:imgQR={{ data }} on:qr:init={(e) => console.log(e.detail /** ImgElement */)} alt="qr" />

<ImgQR
  {data}
  on:qr:init={(e) => console.log(e.detail /** ImgElement */)}
  on:qr:logofetch={(e) => console.log(e.detail /** string, the logo as base64 */)}
/>

Happy making QR! πŸ‘¨β€πŸ’»

Edit this page on Github