Reference

Rune documentation.

Getting started

Rune is a framework-agnostic QR code library. Install the adapter for your framework, or the core for a plain SVG string that works anywhere.

$pnpm add @kroszborg/rune-react
$pnpm add @kroszborg/rune-vue
$pnpm add @kroszborg/rune-wc
$pnpm add @kroszborg/rune # core / SSR string API

React:

import { QRCode } from '@kroszborg/rune-react';

export default function App() {
  return (
    <QRCode
      value="https://example.com"
      dots={{ style: 'rounded' }}
      corners={{ square: { style: 'extra-rounded' } }}
    />
  );
}

Anywhere (server, edge, Node, workers):

import { toSVGString } from '@kroszborg/rune';

const svg = toSVGString({ value: 'https://example.com', dots: { style: 'rounded' } });

Every package (below) accepts the exact same RuneOptions object.

PackageWhat it is
@kroszborg/runeCore: encoder, renderer, exports, data builders, presets. Zero runtime deps.
@kroszborg/rune-reactReact <QRCode> (web). Also the base for React Native.
@kroszborg/rune-vueVue 3 <QRCode>.
@kroszborg/rune-wcVanilla renderRune() + a <rune-qr> Web Component.
@kroszborg/rune-decodeDecoder: read a QR back from a matrix or image.
@kroszborg/rune-cliThe rune CLI: generate or decode from the terminal.

RuneOptions

The single options object accepted by every renderer and adapter.

PropTypeDefaultDescription
valuestring-Data to encode (required).
sizenumber256Output width/height in px.
marginnumber4Quiet zone in modules.
dots{ style, color, gradient }-Data-module style and fill.
cornersCornerOptions-Finder ring + core styles and fills.
backgroundstring | BackgroundOptions'#ffffff'Color, gradient, or image. 'transparent' allowed.
logoLogoOptions-Center logo (auto-raises ECL).
frameFrameOptions-Outer frame + CTA text.
qr{ errorCorrectionLevel, version, mask }-Encoding controls.
presetPresetName-Named base style; explicit options win.
ariaLabelstring'QR code: {value}'Accessible label on the <svg>.

Dot styles

Set with dots.style. Eight styles; rounded and extra-rounded connect adjacent modules for a fluid look.

square
dot
rounded
extra-rounded
classy
classy-rounded
diamond
star
<QRCode value="..." dots={{ style: 'classy-rounded' }} />

Finder styles

The three corner markers. corners.square styles the 7×7 ring; corners.dot styles the inner 3×3 block. Each takes its own color or gradient.

Ring (corners.square.style)

square
rounded
extra-rounded
circle
leaf

Core (corners.dot.style)

square
rounded
dot
FieldType
corners.square.style'square' | 'rounded' | 'extra-rounded' | 'circle' | 'leaf'
corners.square.colorstring
corners.square.gradientGradient
corners.dot.style'square' | 'rounded' | 'dot'
corners.dot.color / gradientstring | Gradient

Colors & gradients

Every element (dots, each finder part, background) takes a solid color or a gradient. A gradient is linear or radial with any number of stops.

solid
linear
radial
Gradient fieldTypeNotes
type'linear' | 'radial'
rotationnumberDegrees, linear only.
stops{ offset, color }[]offset is 0-1.
dots={{ gradient: {
  type: 'linear', rotation: 45,
  stops: [{ offset: 0, color: '#0f7a5c' }, { offset: 1, color: '#0b6b4f' }],
} }}

Background

Pass a color string, or a BackgroundOptions object for a gradient or image. 'transparent' is accepted (useful for overlaying).

FieldTypeDescription
colorstringSolid fill, or 'transparent'.
gradientGradientGradient fill behind the modules.
imagestringImage URL rendered behind the modules.
background="transparent"
// or
background={{ gradient: { type: 'radial', stops: [...] } }}

Frame & CTA

An outer frame with an optional call-to-action label.

SCAN ME
FieldTypeDescription
style'none' | 'square' | 'rounded'Border shape. 'none' draws text only.
textstringCTA label, e.g. "SCAN ME".
position'bottom' | 'top'Where the text band sits.
color / textColorstringFrame and text colors.
fontstringCSS font-family for the label.

Error correction

Higher levels recover from more damage but hold less data. Set with qr.errorCorrectionLevel. You can also pin the version (1-40) and mask (0-7); both are chosen automatically by default.

LevelRecoveryUse when
L~7%Clean environments, minimal data.
M~15%General purpose (default).
Q~25%Print, harsher conditions.
H~30%Codes with a center logo.

Presets

Named starting styles. Pass preset; any explicit option you also set wins over the preset.

minimal
dots
fluid
mint
midnight
sunset
<QRCode value="..." preset="mint" />

Data builders

Turn structured input into correctly-escaped QR content. Import with import { data } from '@kroszborg/rune' and pass the result as value.

data.url('example.com')
data.wifi({ ssid: 'Home', password: 'hunter2', encryption: 'WPA' })
data.email({ to: 'a@b.com', subject: 'Hi', body: '...' })
data.sms({ to: '+15551234', body: 'hi' })
data.tel('+15551234')
data.geo({ lat: 26.9124, lng: 75.7873 })
data.vcard({ fullName: 'Ada Lovelace', email: 'ada@x.com', phone: '+1555' })
data.mecard({ fullName: 'Ada Lovelace', phone: '+1555' })
data.event({ title: 'Launch', start: '2026-07-14T09:00Z', end: '2026-07-14T10:00Z' })
data.crypto({ coin: 'bitcoin', address: '1abc', amount: 0.5 })

Export

The core exports SVG anywhere; raster and PDF live in @kroszborg/rune/node so the browser bundle stays free of native binaries.

FunctionReturnsWhere
toSVGString(o)stringanywhere (sync)
renderToParts(o)SvgPartsanywhere (adapters)
toDataURL(o, r?)Promise<string>browser (Canvas)
toBuffer(o, r?)Promise<Uint8Array>node (/node)
toPDF(o)Promise<Uint8Array>node (/node)

RasterOptions: format ('png' | 'jpeg' | 'webp'), quality (0-1), background.

import { toBuffer, toPDF } from '@kroszborg/rune/node';

const png = await toBuffer({ value: '...', size: 512 }, { format: 'png' });
const pdf = await toPDF({ value: '...', size: 512 });

Decoding

@kroszborg/rune-decode reads a QR back into its data, with full Reed-Solomon error correction.

import { decode, decodeMatrix } from '@kroszborg/rune-decode';

// From raw RGBA pixels (e.g. a canvas ImageData)
const result = decode({ data, width, height });
if (result) console.log(result.text, result.version, result.ecl);

// From a boolean module matrix
const { text } = decodeMatrix(modules); // modules[y][x], true = dark
FunctionInputReturns
decode(img){ data, width, height }MatrixDecodeResult | null
decodeMatrix(m)boolean[][]MatrixDecodeResult

MatrixDecodeResult = { text, version, ecl, mask }.

CLI

@kroszborg/rune-cli generates and decodes from the terminal.

# generate
rune "https://example.com" -o qr.png --dots rounded --preset mint
rune "https://example.com" --gradient "#0f7a5c,#12946e,45" -o qr.pdf
rune "SCAN ME" --frame "SCAN ME" -o cta.svg     # no -o prints SVG to stdout

# decode
rune decode qr.png
FlagDescription
-o, --outOutput file (.svg .png .jpeg .webp .pdf). Stdout SVG if omitted.
-s, --size / -m, --marginSize in px / quiet-zone modules.
--eclL | M | Q | H.
--dots / --dot-colorDot style / color.
--gradient "a,b,r"Linear gradient from,to,rotation.
--square / --coreFinder ring / core style.
--bg / --frame / --logo / --presetBackground, CTA frame, logo, preset.

Frameworks

React

Accepts every RuneOptions prop, plus style, className, and logoElement (a React node overlaid in the center).

import { QRCode } from '@kroszborg/rune-react';
<QRCode value="..." dots={{ style: 'rounded' }} logoElement={<MyLogo />} qr={{ errorCorrectionLevel: 'H' }} />

Vue 3

<script setup>
import { QRCode } from '@kroszborg/rune-vue';
</script>
<template>
  <QRCode value="..." :dots="{ style: 'rounded' }" />
</template>

Web Component (vanilla)

Attributes for simple cases; set the .options property for the full object.

import { register } from '@kroszborg/rune-wc';
register();
// <rune-qr value="..." dot-style="rounded" preset="mint"></rune-qr>
// el.options = { value: '...', dots: { gradient: {...} }, frame: { text: 'SCAN ME' } };

React Native

import { SvgXml } from 'react-native-svg';
import { toSVGString } from '@kroszborg/rune';
const svg = toSVGString({ value: '...', dots: { style: 'rounded' } });
export default () => <SvgXml xml={svg} width={256} height={256} />;

Svelte, Solid, Astro, Angular, Lit

No dedicated package needed - inject the string from toSVGString, or use the <rune-qr> Web Component.

const svg = toSVGString({ value: '...', dots: { style: 'rounded' } });

{@html svg}                 // Svelte
<div innerHTML={svg} />      // Solid
<Fragment set:html={svg} /> // Astro
<div [innerHTML]="svg">     // Angular (sanitizer-bypassed)
<rune-qr value="..."></rune-qr> // Lit / Alpine / plain HTML