@svelte-put/qr
GithubCompatible with or powered directly by Svelte runes.
Installation
npm install --save-dev @svelte-put/qr
pnpm add -D @svelte-put/qr
yarn add -D @svelte-put/qr
New to Svelte 5? See Migration Guides.
Kudos
This package is made possible by headless-qr 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, for example), - 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 snippet: 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"
margin={4}
>
{#snippet svg({ attributes, innerHTML })}
<svg {...attributes} class="**:fill-blue-500">
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
{@html innerHTML}
</svg>
{/snippet}
</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 flex-col items-center gap-2">
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
{@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 custom snippet: useful if you need to use component and have access to
HTMLImageElement
.
<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"
>
{#snippet img({ src })}
<img {src} alt="qr" />
{/snippet}
</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.
<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 flex-col items-center gap-2">
<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
*/
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 option to {@link https://github.com/Rich-Harris/headless-qr | headless-qr},
* default to 0,
*/
version?: number;
/**
* Error correction level, one of {'L', 'M', 'Q', 'H'},
* passed as option to {@link https://github.com/Rich-Harris/headless-qr | headless-qr},
* default to M,
*/
correction?: 'L' | 'M' | 'Q' | 'H';
/**
* @deprecated use `version` instead
*/
typeNumber?: QRCodeOptions['version'];
/**
* @deprecated use `correction` instead
*/
errorCorrectionLevel?: QRCodeOptions['correction'];
};
Events
All rendering strategies share a qrinit
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 qrlogofetch
, 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 }} onqrinit={(e) => console.log(e.detail /** SVGElement */)} />
<SvgQR {data} onqrinit={(e) => console.log(e.detail /** SVGElement */)} />
<img use:imgQR={{ data }} onqrinit={(e) => console.log(e.detail /** ImgElement */)} alt="qr" />
<ImgQR
{data}
onqrinit={(e) => console.log(e.detail /** ImgElement */)}
onqrlogofetch={(e) => console.log(e.detail /** string, the logo as base64 */)}
/>
Migration Guides
V1 -> V2 (Svelte 5 in Runes mode)
When migrating to V2, you will need to update event directives to standard attribute (remove :
)
<svg use:svgQR on:qr:init>
<img use:imgQR on:qr:init>
<svg use:svgQR onqrinit>
<img use:imgQR onqrinit>
<SvgQR on:qr:init>
<SvgQR onqrinit>
<ImgQR on:qr:init on:qr:logofetch>
<ImgQR onqrinit onqrlogofetch>
Default slot
for svg and img components are deprecated in favor for the svg
and img
Svelte snippets, respectively:
<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
>
{#snippet svg({ attributes, html })}
<svg {...attributes}>
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
{@html innerHTML}
</svg>
{/snippet}
</QR>
<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
>
{#snippet img({ src })}
<img {src} alt="qr" />
{/snippet}
</QR>
Happy making QR! 👨💻