---
title: QR Code
description: QR code generator
visibility: guest
draft: false
---

# QR Code

The `<x-wirekit::qr-code>` component generates a QR code as inline SVG from any string value. It uses the [bacon/bacon-qr-code](https://github.com/Bacon/BaconQrCode) PHP library for server-side generation — no JavaScript required.

## Basic Usage

<!-- markdownlint-disable MD034 -->

:::preview{title="Basic QR Code"}
<x-wirekit::qr-code value="https://wirekit.app" />
:::

<!-- markdownlint-enable MD034 -->

## Custom Size

The `size` prop controls both width and height in pixels:

<!-- markdownlint-disable MD034 -->

:::preview{title="Different Sizes"}
<x-wirekit::qr-code value="https://wirekit.app" :size="100" />

<x-wirekit::qr-code value="https://wirekit.app" :size="150" />

<x-wirekit::qr-code value="https://wirekit.app" :size="200" />
:::

## Custom Colors

Use `color` for the foreground modules and `background` for the quiet zone. Both accept any CSS hex color:

:::preview{title="Colored QR Codes"}
<x-wirekit::qr-code value="https://wirekit.app" color="#1e40af" background="#dbeafe" :size="150" />

<x-wirekit::qr-code value="https://wirekit.app" color="#166534" background="#dcfce7" :size="150" />

<x-wirekit::qr-code value="https://wirekit.app" color="#9333ea" background="#f3e8ff" :size="150" />

<x-wirekit::qr-code value="https://wirekit.app" color="#ffffff" background="#18181b" :size="150" />
:::

<!-- markdownlint-enable MD034 -->

```blade
{{-- Blue on light blue --}}
<x-wirekit::qr-code value="..." color="#1e40af" background="#dbeafe" />

{{-- Inverted: white on dark --}}
<x-wirekit::qr-code value="..." color="#ffffff" background="#18181b" />
```

## Error Correction Level

Higher error correction allows the QR code to remain scannable even when partially obscured (e.g. by a logo overlay). The trade-off is a denser pattern with more modules:

<!-- markdownlint-disable MD034 -->

:::preview{title="Error Correction Levels"}
<x-wirekit::row align="end" gap="lg" wrap>
    <div style="text-align: center;">
        <x-wirekit::qr-code value="https://wirekit.app" errorCorrection="L" :size="130" />
        <div style="font-size: 0.75rem; margin-top: 0.5rem;">L (7%)</div>
    </div>
    <div style="text-align: center;">
        <x-wirekit::qr-code value="https://wirekit.app" errorCorrection="M" :size="130" />
        <div style="font-size: 0.75rem; margin-top: 0.5rem;">M (15%)</div>
    </div>
    <div style="text-align: center;">
        <x-wirekit::qr-code value="https://wirekit.app" errorCorrection="Q" :size="130" />
        <div style="font-size: 0.75rem; margin-top: 0.5rem;">Q (25%)</div>
    </div>
    <div style="text-align: center;">
        <x-wirekit::qr-code value="https://wirekit.app" errorCorrection="H" :size="130" />
        <div style="font-size: 0.75rem; margin-top: 0.5rem;">H (30%)</div>
    </div>
</x-wirekit::row>
:::

<!-- markdownlint-enable MD034 -->

Use `H` (30% correction) when you plan to overlay a logo on the QR code.

## Margin (Quiet Zone)

The `margin` prop controls the white border around the QR code in module units. The [QR standard](https://www.iso.org/standard/62021.html) recommends at least 4 modules, but you can reduce it for tight layouts:

<!-- markdownlint-disable MD034 -->

:::preview{title="Margin (Quiet Zone)"}
<x-wirekit::row align="end" gap="lg" wrap>
    <div style="text-align: center;">
        <x-wirekit::qr-code value="https://wirekit.app" :margin="0" :size="130" />
        <div style="font-size: 0.75rem; margin-top: 0.5rem;">margin=0</div>
    </div>
    <div style="text-align: center;">
        <x-wirekit::qr-code value="https://wirekit.app" :margin="2" :size="130" />
        <div style="font-size: 0.75rem; margin-top: 0.5rem;">margin=2</div>
    </div>
    <div style="text-align: center;">
        <x-wirekit::qr-code value="https://wirekit.app" :margin="4" :size="130" />
        <div style="font-size: 0.75rem; margin-top: 0.5rem;">margin=4</div>
    </div>
</x-wirekit::row>
:::

<!-- markdownlint-enable MD034 -->

## Complex Examples

### WiFi Network

Encode WiFi credentials using the [standard WiFi QR format](https://github.com/zxing/zxing/wiki/Barcode-Contents#wi-fi-network-config). Scanning this QR connects the device automatically:

:::preview{title="WiFi Network QR"}
<x-wirekit::row align="center" gap="lg" wrap>
    <x-wirekit::qr-code value="WIFI:T:WPA;S:GuestNetwork;P:welcome2024;;" :size="180" errorCorrection="M" />
    <div>
        <strong>GuestNetwork</strong><br>
        Security: WPA/WPA2<br>
        Password: welcome2024<br>
        Scan to connect automatically
    </div>
</x-wirekit::row>
:::

### vCard Contact

Encode contact information as a [vCard](https://en.wikipedia.org/wiki/VCard) — scanning adds the contact to the phone's address book:

<!-- markdownlint-disable MD034 -->

:::preview{title="vCard Contact QR"}
<x-wirekit::row align="center" gap="lg" wrap>
    <x-wirekit::qr-code value="BEGIN:VCARD
VERSION:3.0
FN:Jane Smith
ORG:Acme Inc.
TEL:+1-555-123-4567
EMAIL:jane@acme.com
URL:https://acme.com
END:VCARD" :size="180" errorCorrection="M" color="#1e293b" />
    <div>
        <strong>Jane Smith</strong><br>
        Acme Inc.<br>
        +1-555-123-4567<br>
        jane@acme.com<br>
        Scan to add contact
    </div>
</x-wirekit::row>
:::

<!-- markdownlint-enable MD034 -->

### Branded with Logo Overlay

Use high error correction (`H`) so the QR remains scannable with a logo on top:

<!-- markdownlint-disable MD034 -->

:::preview{title="Branded with Logo Overlay"}
<div style="position: relative; display: inline-block;">
    <x-wirekit::qr-code value="https://wirekit.app" :size="250" errorCorrection="H" />
    <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 3rem; height: 3rem; background: white; border-radius: 0.375rem; padding: 0.25rem; display: flex; align-items: center; justify-content: center;">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" style="width: 2rem; height: 2rem; color: var(--color-wk-accent);" aria-hidden="true">
            <path stroke-linecap="round" stroke-linejoin="round" d="m3.75 13.5 10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75Z" />
        </svg>
    </div>
</div>
:::

<!-- markdownlint-enable MD034 -->

Keep the logo under ~30% of the QR area so the error correction can recover the obscured modules.

```blade
<div class="relative inline-block">
    <x-wirekit::qr-code
        value="https://wirekit.app"
        :size="250"
        errorCorrection="H"
    />
    <img
        src="/logo.svg"
        alt=""
        aria-hidden="true"
        class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-12 h-12 bg-white p-1 rounded"
    />
</div>
```

### Dynamic Values

Use Blade expressions to encode dynamic content:

```blade
{{-- Route URL --}}
<x-wirekit::qr-code :value="route('invite', $token)" />

{{-- Email mailto --}}
<x-wirekit::qr-code :value="'mailto:' . $user->email" />

{{-- Coupon code --}}
<x-wirekit::qr-code :value="$couponCode" :size="150" />
```

## SVG Output

The component always renders SVG — never a raster image. This means:

- **Infinitely scalable** — looks sharp on any screen density (Retina, 4K)
- **Styleable** — the SVG respects the `color` and `background` props
- **Printable** — vector output at any resolution
- **Lightweight** — typically 2–5 KB inline SVG, no external requests
- **Accessible** — wrapped in `role="img"` with `aria-label`

The SVG is rendered inline in the DOM (not as `<img src="...">`) so it's part of the page's DOM tree and can be styled with CSS if needed.

## Requirements

This component requires the [bacon/bacon-qr-code](https://github.com/Bacon/BaconQrCode) PHP package:

```bash
composer require bacon/bacon-qr-code
```

The package is a **suggested** dependency of WireKit, not a required one. If the package is not installed, the component renders a styled placeholder instead of a QR code.

## Fallback Behavior

When [bacon/bacon-qr-code](https://github.com/Bacon/BaconQrCode) is not installed or the `value` is empty, the component renders a placeholder `<div>` with the text "QR Code" — styled with WireKit design tokens (muted background, border, rounded corners). This ensures the layout does not break.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | `''` | The text or URL to encode |
| `size` | `int` | `200` | Width and height in pixels |
| `color` | `string` | `'#000000'` | Foreground (module) color as hex |
| `background` | `string` | `'#ffffff'` | Background color as hex |
| `errorCorrection` | `string` | `'L'` | Error correction level: `L` (7%), `M` (15%), `Q` (25%), `H` (30%) |
| `margin` | `int` | `4` | Quiet zone width in QR modules |
| `accessibleLabel` | `string\|null` | `null` | Accessible name announced by screen readers. Defaults to `"QR code"` when omitted — pass a purpose-describing label like `"Scan to install WireKit"` rather than letting the encoded URL leak as the announcement. |
| `scope` | `string\|null` | `null` | Scoped personalization key |

## Accessibility

- Container: `role="img"` — identifies the element as an image to assistive technology
- `aria-label="QR code for {value}"` — provides a descriptive accessible name including the encoded content
- The QR code is purely visual — screen readers announce the label instead of attempting to parse the SVG paths

::: tip
If the encoded `value` contains sensitive data (like API keys), consider overriding the `aria-label` to avoid exposing it to screen readers: `aria-label="QR code for your API key"`.
:::

## Keyboard Interaction

This component is purely presentational and does not respond to keyboard input.

## Pitfalls

- **Don't QR-encode personally identifiable data.** QR codes are public — anyone within camera range can capture them. Encode opaque tokens and resolve server-side.

## Design Tokens

The rendered QR code itself is a black-on-transparent SVG (the `bacon/bacon-qr-code` package emits paths in `currentColor`-equivalent black for maximum scanner contrast). Token usage is concentrated on the placeholder fallback and the surrounding container:

| Token | Used for |
| --- | --- |
| `--text-wk-sm` | Placeholder label font size |
| `--color-wk-text-muted` | Placeholder label text |
| `--color-wk-bg-muted` | Placeholder background |
| `--color-wk-border` | Placeholder border |
| `--border-wk-width` | Placeholder border width |
| `--radius-wk-md` | Placeholder border radius |

## Personalization

Override classes globally via `WireKit::personalize()`:

```php
use Pushery\WireKit\WireKit;

WireKit::personalize('qr-code', [
    'base' => 'inline-block p-4 bg-white rounded-lg shadow',
]);
```

## Further Reading

- [bacon/bacon-qr-code](https://github.com/Bacon/BaconQrCode) — the PHP QR code generation library used by this component
- [MDN: `role="img"`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/img_role) — the ARIA role used on the container
- [QR Code Standard (ISO/IEC 18004)](https://www.iso.org/standard/62021.html) — the international standard for QR codes
- [ZXing QR Code Wiki](https://github.com/zxing/zxing/wiki/Barcode-Contents) — common QR code content formats (URL, WiFi, vCard, etc.)
