Skip to content

@carrot/qr-vue ​

tsvue

Canvas-based QR code renderer with a Vue 3 component. Supports multiple render styles, custom finder patterns, centre cutouts, and retina-aware rendering.

Installation ​

ts
import { CarrotQr } from '@carrot/qr-vue';
// or framework-agnostic:
import { renderToCanvas } from '@carrot/qr-vue';

Peer dependency: vue ^3.5.30. Runtime dependency: @carrot/qr.

Architecture ​

Renderer ​

The core renderer (render.ts) is framework-agnostic - it takes a canvas, a QrCode, a QrPixelGrid, and options, and draws everything via Canvas 2D. The pipeline:

  1. Background - fill or clear
  2. Data modules - dispatched by variant:
    • basic - filled rectangles with 0.5px overlap for hairline elimination
    • dots - circles at configurable size fraction
    • smooth - single-path outline per module with convex/concave corner classification based on 8-neighbour analysis
  3. Finder patterns - drawn separately in square, rounded-rect, or circle style
  4. Centre cutout - exclusion zone that skips data modules + optional background overlay

Smooth Variant ​

The smooth renderer classifies each module's four corners by inspecting the two adjacent cardinal neighbours and the diagonal:

  • Neither cardinal present → convex quarter-circle (isolated module becomes a circle)
  • One cardinal present → square corner
  • Both cardinals, diagonal present → square corner
  • Both cardinals, diagonal absent → concave quarter-circle notch

Concave fills extend into the empty diagonal cell as small arc segments, creating organic blob shapes.

Vue Component ​

CarrotQr wraps the renderer with reactive props. It:

  • Reads CSS custom properties (--qr-fg, --qr-bg, --qr-accent) as colour defaults
  • Auto-enables centre cutout when slot content is provided
  • Re-renders on any prop change via watch + nextTick
  • Renders at 2x DPR for retina displays

File Structure ​

src/
├── index.ts                    # Public API barrel
├── render.ts                   # Canvas renderer (framework-agnostic)
├── types/
│   └── types.ts                # QrRenderOptions, CenterCutout, QrProps
├── components/
│   └── CarrotQr.vue            # Vue 3 component
└── styles/
    └── qr.css                  # Component styles

Dependencies ​

DependencyKind
@carrot/qrruntime
vuepeer

Build ​

bash
npm run build

Builds via vue-tsc --noEmit && vite build. Output lands in dist/.


Usage Guide ​

Canvas-based QR code renderer and Vue component with render variants, finder styles, and centre cutout for logos.

Import ​

ts
import { CarrotQr } from '@carrot/qr-vue';

Common Patterns ​

1. Basic component usage ​

vue
<CarrotQr url="https://example.com" />

Defaults: smooth variant, circle finders, white foreground, transparent background, high ECC.

2. With a logo cutout ​

vue
<CarrotQr url="https://example.com" :cutout="0.2">
    <img src="/logo.svg" width="40" height="40" />
</CarrotQr>

Slot content is centred in the cutout area. The cutout auto-enables when slot content is provided (defaults to 0.2 size).

3. Render variants ​

vue
<!-- Smooth blob style (default) -->
<CarrotQr url="..." variant="smooth" />

<!-- Circular dots -->
<CarrotQr url="..." variant="dots" :dot-size="0.6" />

<!-- Plain squares -->
<CarrotQr url="..." variant="basic" />

4. Finder pattern styles ​

vue
<CarrotQr url="..." finder-style="circle" />
<CarrotQr url="..." finder-style="rounded" />
<CarrotQr url="..." finder-style="square" />

5. Colours via props ​

vue
<CarrotQr url="..." fg="#1a1a2e" bg="#ffffff" accent="#e94560" />

6. Colours via CSS custom properties ​

css
.my-qr {
    --qr-fg: var(--color-text);
    --qr-bg: var(--color-surface);
    --qr-accent: var(--color-primary);
}
vue
<CarrotQr url="..." class="my-qr" />

Props override CSS custom properties when both are set.

7. Framework-agnostic renderer ​

Use renderToCanvas directly without Vue:

ts
import { create, createGrid, ErrorCorrection } from '@carrot/qr';
import { renderToCanvas } from '@carrot/qr-vue';

const code = create('https://example.com', ErrorCorrection.High);
const grid = createGrid(code);
const canvas = document.getElementById('qr') as HTMLCanvasElement;

renderToCanvas(canvas, code, grid, {
    variant: 'smooth',
    foreground: '#ffffff',
    background: 'transparent',
    finderStyle: 'circle',
    centerCutout: { size: 0.2 },
});

8. Offscreen rendering ​

ts
import { renderToOffscreen } from '@carrot/qr-vue';

const canvas = renderToOffscreen(code, grid, 400, {
    variant: 'dots',
    foreground: '#000000',
    background: '#ffffff',
});

// Use as image source
const dataUrl = canvas.toDataURL();

Tips ​

  • Use ecc="high" with cutouts - the default. Centre cutouts destroy data modules, so high ECC ensures the code remains scannable.
  • Smooth variant looks best at larger sizes - the convex/concave corner detection creates organic blob shapes that shine at 200px+.
  • CSS custom properties are read at render time - they react to theme changes without prop updates.

Carrot