Forms QR Code

QR Code

Pure client-side QR code generation — no external libraries. Add data-wf-qr to any element and supply content via a data-wf-content attribute, an inline <script type="application/json"> block, or a remote fetch via data-wf-src. The component builds the QR matrix and renders a single-path SVG fully in the browser — theme-aware, instantly downloadable. Supports byte mode, versions 1–10 (≈ 174 chars at EC level M).

Inline Content

The simplest init: set data-wf-content to the text or URL to encode. A label and custom size are optional.

Inline JSON • EC level H
HTML
<!-- 1. Attribute — simplest -->
<div data-wf-qr
     data-wf-content="https://example.com"
     data-wf-size="200"
     data-wf-label="Scan me">
</div>

<!-- 2. Inline JSON — matches wf-chart pattern -->
<div data-wf-qr data-wf-size="200" data-wf-ec-level="H">
  <script type="application/json">
  { "content": "bitcoin:address?amount=0.001&label=Order+123" }
  </script>
</div>

Remote Fetch

Use data-wf-src to fetch content from the server. The component shows a skeleton loader while waiting, then renders the QR from the content key in the JSON response. Optional data-wf-params appends query parameters to the request.

HTML
<div data-wf-qr
     data-wf-src="/api/payment/qr"
     data-wf-params='{"order_id":"<?php echo $order_id; ?>"}'
     data-wf-size="200"
     data-wf-label="Scan with your wallet">
</div>
Server Response
// Required: a "content" key with the string to encode
{ "content": "bitcoin:address?amount=0.001&label=Order+456" }

// The component also accepts the raw string as the entire response body
"bitcoin:address?amount=0.001"
PHP
case 'getPaymentQr':
    $orderId = trim($_GET['order_id'] ?? '');
    $order   = Order::find($orderId);
    if (!$order) json_out(['type' => 'negative', 'message' => 'Order not found.'], 404);

    // Build a Bitcoin URI or any other content string
    $uri = 'bitcoin:' . $order->wallet_address
        . '?amount=' . $order->amount_btc
        . '&label=' . rawurlencode('Order #' . $orderId);

    json_out(['content' => $uri]);

Ajax Action Bridge

Add data-wf-qr-target="#el" to any wf-ajax-action trigger. When the action succeeds and the server returns a content key, the component re-renders automatically — no JavaScript required. The example below lets the user switch blockchain network and instantly updates the wallet address QR.

Selecting a network calls the server and updates the QR code with the matching wallet address.

HTML
<!-- QR target receives updates when server returns { content: "…" } -->
<div id="pay-qr" data-wf-qr data-wf-size="200"
     data-wf-content="bitcoin:1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2">
</div>

<select data-wf-ajax-action="getAddress"
        data-wf-url="/api/wallets"
        data-wf-qr-target="#pay-qr">
  <option value="btc">Bitcoin (BTC)</option>
  <option value="eth">Ethereum (ETH)</option>
  <option value="usdc">USDC (Polygon)</option>
</select>
PHP — server returns content key
case 'getAddress':
    $chain = trim($_REQUEST['value'] ?? 'btc');

    $wallets = [
        'btc'  => 'bitcoin:1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2',
        'eth'  => 'ethereum:0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
        'usdc' => 'polygon:0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
    ];

    json_out(['content' => $wallets[$chain] ?? $wallets['btc']]);

Crypto Payment Integration

Pair data-wf-qr with data-wf-poll for a complete payment flow: the QR code shows the wallet address while the poll component monitors the transaction status and redirects on confirmation.

HTML
<!--
  Complete crypto payment page.
  Both components share the same order_id.
  wf-qr fetches the wallet address from the server.
  wf-poll monitors payment status and redirects on confirmation.
-->

<div data-wf-qr
     data-wf-src="/api/payment/qr"
     data-wf-params='{"order_id":"<?php echo $order_id; ?>"}'
     data-wf-size="220"
     data-wf-label="Scan with your wallet"
     id="pay-qr">
</div>

<div data-wf-poll
     data-wf-url="/api/payment/status"
     data-wf-params='{"order_id":"<?php echo $order_id; ?>"}'
     data-wf-interval="3s"
     data-wf-timeout="30m"
     data-wf-stop-on="confirmed,expired"
     data-wf-redirect-on="confirmed"
     data-wf-redirect-url="/membership"
     data-wf-redirect-delay="3s"
     data-wf-parent="#pay-status"
     data-wf-timer="#pay-countdown">
</div>

<div id="pay-status">Waiting for payment…</div>
<span id="pay-countdown">30:00</span>

Data Attributes

Attribute Default Description
data-wf-qr Required. Presence marker. No value needed.
data-wf-content="text" empty Text or URL to encode. Simplest init; can also be supplied via inline JSON or data-wf-src.
data-wf-size="200" 200 Rendered SVG width and height in px. The quiet-zone modules are included within this dimension.
data-wf-ec-level="M" M Error correction level: L (7%) | M (15%) | Q (25%) | H (30%). Higher levels increase QR size but add recovery capability.
data-wf-color="#000" CSS --wf-foreground Dark module color. Inherits from the --wf-foreground CSS variable when empty, so dark-mode is automatic.
data-wf-background="" transparent Light module color. Transparent by default so the QR blends into any card background.
data-wf-margin="4" 4 Quiet zone width in modules. The QR standard recommends a minimum of 4.
data-wf-label="text" empty Optional caption rendered below the QR image.
data-wf-label-size="13" 13 Caption font-size in px.
data-wf-src="/url" empty GET-fetch URL. Component shows a skeleton loader while fetching, then renders from { "content": "…" } in the response.
data-wf-params='{"k":"v"}' empty JSON object appended as query parameters to the data-wf-src URL.
data-wf-csrf-header="X-CSRF-Token" X-CSRF-Token Header name for the CSRF token, read from <meta name="csrf-token">. Set to "" to disable.

Events & API

Event When detail
wf:qr-ready After first render (attribute, inline JSON, or remote fetch) { content, size }
wf:qr-update After render() re-draw (e.g. from ajax-action bridge) { content, size }
wf:qr-error Content too long for versions 1–10 or invalid input { content, error }
Public API
const qr = document.querySelector('#pay-qr')._wfQr

// Re-encode and redraw with new content
qr.render('https://example.com/updated')

// Download the current QR as an SVG file
qr.download('payment-qr.svg')

// Get the raw SVG markup string (for embedding or sending to a server)
const svg = qr.toSVG()

// Full teardown
qr.destroy()
Event Listening
document.querySelector('#pay-qr').addEventListener('wf:qr-ready', e => {
    console.log('QR ready:', e.detail.content)
})

document.querySelector('#pay-qr').addEventListener('wf:qr-error', e => {
    console.warn('QR failed:', e.detail.error.message)
})