Skip to main content

QR Code

Info:Media
11

A themeable QR code that derives its colors from the active theme, drops an icon in the middle, and can fall back to guaranteed-scannable black-on-white.

barcode 2d barcode link url deep link scan vcard wifi

Live demo

live · @xtyle/astro

QR Code

A themed link

Encode any string; the modules ink themselves from the active theme (--fg-0 on --bg-0), so a QR that matches the surrounding UI is the default, not a manual export. The encoder runs in the browser, so switch the theme and the code recolors live.

https://xtyle.dev

WIFI join

mailto:

Module shapes

Draw each dark cell as a full square (densest, scans most reliably), a dot, or a rounded square. The finder patterns always stay solid so a reader can still lock on, and the curved shapes anti-alias while squares render crisp.

square

dot

rounded

A mark in the middle

Drop any xtyle icon in the center with icon (or a bitmap with logo), sized by iconSize (sm/md/lg/xl, or an exact iconScale). Error correction bumps to level H automatically. By default the mark knocks a clean hole in the modules; set iconOverlay to lay it over the code the way a printed logo does, letting error correction recover the covered modules, and iconOutline for a halo so it stays distinct. Add frame to print the payload beneath for anyone who'd rather type the link than scan it.

knockout (default)

overlay + outline

iconSize xl

sm

md

lg

xl

An interactive frame

With frame, the payload prints beneath the code as a real, followable link (when it is one), so a viewer can click through instead of scanning. Add modeToggle for a small button that swaps between the themed and bitonal renderings live, so anyone whose scanner struggles with the themed colors can flip to guaranteed black-on-white on the spot. Only safe link schemes are ever made clickable.

Scannability modes

Scannability is a contract, not a hope. theme inks from the theme (and flags a low-contrast pairing via data-contrast); bitonal forces the guaranteed black-on-white a reader never misses, whatever the theme; auto keeps the theme colors while they clear the scannability floor and silently drops to bitonal when they don't. The floor is xtyle's own contrast audit pointed at a new surface.

theme

bitonal

auto

Error-correction levels

L (~7%), M (~15%), Q (~25%), and H (~30%) set how much of the symbol can be lost and still decode. Higher recovers more damage or occlusion at the cost of a denser grid.

L

M

Q

H

QR Code encodes any string into a scannable symbol with a self-contained encoder that runs at build and in the browser alike, so a themed code costs no runtime and no network. It follows ISO/IEC 18004: automatic mode selection (numeric, alphanumeric, or byte over UTF-8), the full error-correction tables for versions 1-40, Reed-Solomon parity, and the eight data masks scored for the cleanest read.

Because the modules ink themselves from the theme (--fg-0 on --bg-0 by default, overridable through the --qr-module / --qr-bg custom properties), a QR that matches the surrounding UI is the default, not a manual export. Drop an icon in the center with icon (any xtyle icon name) or a bitmap with logo, sized by icon-scale to the conventional logo fraction; the component bumps error correction to level H so the mark never costs a byte the scanner needs. By default it knocks a clean hole in the modules and pads the mark against the background; set icon-overlay to instead lay the mark straight over the code the way a printed logo does, letting error correction recover the covered modules, and icon-outline for a background-colored halo so the mark stays distinct against the pattern. module-shape renders squares, dots, or rounded cells; frame wraps the code and prints the payload beneath it so a human can read the link a camera would follow. The load-bearing rule is scannability: mode="theme" inks from the theme and flags a low-contrast pairing, mode="bitonal" forces the guaranteed black-on-white a reader never misses, and mode="auto" measures the live theme and silently falls back to bitonal only when the theme's own colors drop below the scannable floor. The floor is xtyle's own contrast infrastructure pointed at a new surface, so a themed code that would fail to scan is caught, not shipped.

When to use

How this component composes with the rest of the set.

Point data at a URL and drop the code into a Card footer or a Panel so a printed page or a slide carries a scannable link.
Set icon to a brand-shaped xtyle icon (or logo to a bitmap) for a centered mark; error correction bumps to H automatically so it still scans.
Add frame where a human might need to type the link a camera would otherwise follow; the payload prints beneath the symbol in mono.
Reach for mode="bitonal" on anything printed or shown over an uncertain background, and mode="auto" when a themed code should self-downgrade only if its colors can't be scanned.
Override --qr-module / --qr-bg for a bespoke pairing the algorithm didn't derive, but audit it: the contrast floor is there for a reason.

Props

16 props, straight from the manifest.

PropTypeDefaultBindingsDescription
data string
html svelte astro
The payload to encode: a URL, plain text, a `mailto:`/`tel:`/`WIFI:`/`BEGIN:VCARD` string, anything. The encoder picks numeric, alphanumeric, or byte mode and the smallest version that fits.
mode QrMode
theme bitonal auto
theme
html svelte astro
How the two colors are chosen: `theme` inks from the tokens (and flags a low-contrast pairing), `bitonal` forces guaranteed-scannable black-on-white, `auto` uses the theme when it clears the scannability floor and falls back to bitonal when it doesn't.
ecLevel QrEcLevel
L M Q H
M
html svelte astro
Error-correction level: `L` (~7%), `M` (~15%), `Q` (~25%), `H` (~30%) recoverable. Higher survives more damage or occlusion at the cost of density; an injected `icon`/`logo` forces `H`.
icon string
html svelte astro
An xtyle icon name to drop in the center. Bumps error correction to `H` and clears the center modules so the mark never costs a scannable byte.
logo string
html svelte astro
An image URL to drop in the center instead of an `icon`; same sizing, `H` bump, and overlay/knockout behavior.
iconSize QrIconSize
sm md lg xl
md
html svelte astro
The center mark's size as a named preset: `sm` (18%), `md` (24%), `lg` (28%), `xl` (32% of the symbol width). Larger leans harder on error correction; every preset stays scannable in both knockout and overlay at level H.
iconScale number
html svelte astro
An exact fraction of the symbol width for the center mark (clamped to 0.1-0.4), the escape hatch when a preset `iconSize` isn't the size you want. Overrides `iconSize` when set.
iconOverlay boolean false
html svelte astro
Lay the mark over the modules (error correction recovers the covered ones) instead of knocking a hole in them. Pair with `iconOutline` so the mark reads against the pattern.
iconOutline boolean false
html svelte astro
Give the center mark a background-colored halo so it stays distinct against the modules; most useful with `iconOverlay`.
moduleShape QrModuleShape
square dot rounded
square
html svelte astro
How each dark module is drawn: `square` (densest, scans most reliably), `dot`, or `rounded`.
frame boolean false
html svelte astro
Wrap the code in a surface and print the payload beneath it. When the payload is a link (`http(s)`, `mailto:`, `tel:`, or a bare host), the caption renders as a real, followable link rather than plain text.
caption string
html svelte astro
Override the frame's caption text (defaults to the payload). Only shown when `frame` is set.
modeToggle boolean false
html svelte astro
Show a small button on the frame that swaps the rendering between its themed and bitonal (guaranteed black-on-white) modes live, so a viewer can flip to the high-contrast version if their scanner struggles. Requires the runtime.
size number 200
html svelte astro
The rendered pixel size of the symbol.
quietZone number 4
html svelte astro
Modules of empty margin around the symbol. The spec floor is 4; going lower risks a reader that can't find the edges.
label string
html svelte astro
The accessible name announced for the symbol. Defaults to the payload.

Appearance

States

low-contrast

.xtyle-qr[data-contrast="low"]

Set on the figure when the theme colors fall below the scannability floor (in theme mode, or auto before it falls back), so a failing pairing is visible to a linter or a designer.

Anatomy

The named parts that make up the component, with their selectors.

code

.xtyle-qr__code

The square that holds the symbol; sized by size and rounded off the radius scale.

--radius-md

background

.xtyle-qr__bg

The full-bleed background rect behind the modules; inks from --qr-bg (defaulting to --bg-0).

--bg-0

modules

.xtyle-qr__modules

The single path drawing every dark module; inks from --qr-module (defaulting to --fg-0).

--fg-0

logo

.xtyle-qr__logo

The centered icon or bitmap; knocked out of the grid on a background pad, or (overlay) laid over it with an optional halo.

--radius-md

caption

.xtyle-qr__caption

The payload printed beneath the symbol when frame is set, in the mono type; a real link when the payload is one, plain text otherwise.

--fg-1 --font-mono --text-sm

toggle

.xtyle-qr__toggle

The optional button on the frame that swaps between the themed and bitonal renderings.

--fg-0 --fg-1 --bg-0 --radius-md --ring

frame

.xtyle-qr--framed

The optional surrounding surface that groups the code, its caption, and the toggle.

--bg-1 --radius-lg --space-3

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 11/11 consumed tokens produced default register: 299 tokens

Live coverage check against the xtyle-default register (derive(xtyleDefault, { anchors })coverComponent(manifest, register)). Every token this component consumes must be a key the algorithm produces.

--bg-0 --bg-1 --fg-0 --fg-1 --font-mono --radius-lg --radius-md --ring --space-2 --space-3 --text-sm

Accessibility

The symbol is an <svg role="img"> with an aria-label naming the payload, so assistive tech announces the destination a sighted user would scan.
frame prints the payload beneath the code as a real, keyboard-focusable link when it is one (a non-camera path to the same destination), or plain text otherwise. Only safe schemes (http(s), mailto:, tel:) are linkified, so a javascript: payload never becomes a live link.
The modeToggle button is a real <button> with an aria-label and an aria-pressed state reflecting whether the bitonal rendering is active, so the swap is operable and announced.
Scannability is treated as an accessibility contract: theme mode flags a low-contrast pairing via data-contrast, and auto falls back to guaranteed black-on-white rather than shipping a code that can't be read.
Module color and background come from the same tokens the rest of the theme is graded against, so a QR never becomes the one un-audited patch of a themed page.

Code

A themed link

The default: encode a URL and let the modules ink themselves from the active theme.

<xtyle-qr data="https://xtyle.dev"></xtyle-qr>
<script lang="ts">
	import { QrCode } from "@xtyle/svelte";
</script>

<QrCode data="https://xtyle.dev" />
---
import QrCode from "@xtyle/astro/Qr.astro";
---

<QrCode data="https://xtyle.dev" />

Centered icon, framed

Drop an xtyle icon in the middle (error correction bumps to H) and frame the code so the link prints beneath it.

<xtyle-qr
	data="https://xtyle.dev"
	icon="palette"
	frame
	size="240"
></xtyle-qr>
<script lang="ts">
	import { QrCode } from "@xtyle/svelte";
</script>

<QrCode data="https://xtyle.dev" icon="palette" frame size={240} />
---
import QrCode from "@xtyle/astro/Qr.astro";
---

<QrCode data="https://xtyle.dev" icon="palette" frame size={240} />

Overlay logo with an outline

icon-overlay lays the mark straight over the code the way a printed logo does; icon-outline gives it a halo so it stays distinct while error correction recovers the covered modules.

<!-- Lay the mark over the code (error correction recovers the covered modules) -->
<xtyle-qr
	data="https://xtyle.dev"
	icon="palette"
	icon-overlay
	icon-outline
	icon-scale="0.26"
></xtyle-qr>
<script lang="ts">
	import { QrCode } from "@xtyle/svelte";
</script>

<QrCode data="https://xtyle.dev" icon="palette" iconOverlay iconOutline iconScale={0.26} />
---
import QrCode from "@xtyle/astro/Qr.astro";
---

<QrCode data="https://xtyle.dev" icon="palette" iconOverlay iconOutline iconScale={0.26} />

Framed with a live link and swap

frame renders the payload as a real followable link beneath the code, and mode-toggle adds a button that swaps between the themed and bitonal renderings on the spot.

<!-- The caption is a real link; the button swaps themed <-> bitonal live -->
<xtyle-qr data="https://xtyle.dev" frame mode-toggle></xtyle-qr>
<script lang="ts">
	import { QrCode } from "@xtyle/svelte";
</script>

<QrCode data="https://xtyle.dev" frame modeToggle />
---
import QrCode from "@xtyle/astro/Qr.astro";
---

<QrCode data="https://xtyle.dev" frame modeToggle />

Bitonal fallback

Force guaranteed-scannable black-on-white regardless of theme, for print or an uncertain background.

<!-- Guaranteed-scannable black-on-white, whatever the theme -->
<xtyle-qr data="https://xtyle.dev" mode="bitonal"></xtyle-qr>
<script lang="ts">
	import { QrCode } from "@xtyle/svelte";
</script>

<QrCode data="https://xtyle.dev" mode="bitonal" />
---
import QrCode from "@xtyle/astro/Qr.astro";
---

<QrCode data="https://xtyle.dev" mode="bitonal" />

Auto scannability

mode="auto" keeps the theme colors while they clear the scannability floor and silently drops to bitonal when they don't.

<!-- Theme colors when they clear the scannability floor, bitonal when they don't -->
<xtyle-qr data="https://xtyle.dev" mode="auto" module-shape="dot"></xtyle-qr>