Skip to content

Early previewhamur is not on npm yet. The components are being built in the open, follow along on GitHub.

DisplayReact

QR Code

Draws a QR code for a text, such as a link, a ticket or a Wi-Fi setting, as an SVG image that scales without blurring.

Rendered by React 19.3.1

import { QrCode } from '@hamur/react/qr-code'

export default function QRCodeExample() {
  return (
    <QrCode.Root className="qr-code" value="https://example.com/r/42">
      <QrCode.Frame className="qr-code-frame">
        <QrCode.Pattern />
      </QrCode.Frame>
    </QrCode.Root>
  )
}
Not measured yetTests passing in React
Not measured yetSize
Not measured yetMemory
Not measured yetSpeed
[N] commits

Installation

npm i @hamur/react

Not on npm yet. The package goes out under the chosen name.

Anatomy

Import the component and assemble its parts:

<QrCode.Root>
  <QrCode.Frame>
    <QrCode.Pattern />
  </QrCode.Frame>
</QrCode.Root>

// Not in this example: QrCode.DownloadTrigger, QrCode.Overlay

Examples

The same link at level H, with a logo in an Overlay over the middle.

QRCodeLogo.tsx
import { QrCode } from '@hamur/react/qr-code'

export default function QRCodeLogoExample() {
  return (
    <QrCode.Root className="qr-code" value="https://example.com/r/42" errorCorrection="H">
      <QrCode.Frame className="qr-code-frame">
        <QrCode.Pattern />
      </QrCode.Frame>
      <QrCode.Overlay className="qr-code-overlay">
        <svg width="24" height="24" viewBox="0 0 24 24">
          <path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z" />
        </svg>
      </QrCode.Overlay>
    </QrCode.Root>
  )
}

Download

Two DownloadTriggers that save the code as a PNG and as an SVG file named ticket-42.

QRCodeDownload.tsx
import { QrCode } from '@hamur/react/qr-code'

export default function QRCodeDownloadExample() {
  return (
    <QrCode.Root className="qr-code" value="https://example.com/r/42">
      <QrCode.Frame className="qr-code-frame">
        <QrCode.Pattern />
      </QrCode.Frame>
      <div className="qr-code-actions">
        <QrCode.DownloadTrigger className="button" fileName="ticket-42">
          Download PNG
        </QrCode.DownloadTrigger>
        <QrCode.DownloadTrigger className="button" fileName="ticket-42" type="image/svg+xml">
          Download SVG
        </QrCode.DownloadTrigger>
      </div>
    </QrCode.Root>
  )
}

Overflow

A button that swaps the link for a 3000-character text, which marks every part and disables the download.

QRCodeOverflow.tsx
import * as React from 'react'
import { QrCode } from '@hamur/react/qr-code'

const short = 'https://example.com/r/42'
const long = `${short}#${'x'.repeat(2975)}`

export default function QRCodeOverflowExample() {
  const [value, setValue] = React.useState(short)
  return (
    <div className="stack">
      <QrCode.Root className="qr-code" value={value}>
        <QrCode.Frame className="qr-code-frame">
          <QrCode.Pattern />
        </QrCode.Frame>
        <p className="muted qr-code-note">Too long for a QR code</p>
        <QrCode.DownloadTrigger className="button">Download PNG</QrCode.DownloadTrigger>
      </QrCode.Root>
      <button
        type="button"
        className="button"
        onClick={() => setValue(value === short ? long : short)}
      >
        {value === short ? 'Use a long text' : 'Use a short text'}
      </button>
      <p className="muted qr-code-log">{value.length} characters</p>
    </div>
  )
}

API reference

11 props across 5 parts, in React syntax. className, style, render are listed once, under Shared props.

DownloadTriggerQrCode.DownloadTrigger

A button that downloads the symbol as a PNG or SVG file, in the colours the code is shown in. Disabled while the value does not fit. Renders a <button>.

DownloadTrigger props
PropTypeDefault
nativeButtonWhether the component renders a native <button> element when replacing itbooleantrue
fileNameThe name of the downloaded file; the extension of type is added when missing.string'qr-code'
typeThe file format.QrCodeDownloadType'image/png'
scaleThe CSS pixels per module of a PNG, an integer of at least 1.number10
focusableWhenDisabledWhether the button stays focusable when disabled.booleanfalse
DownloadTrigger data attributes
Data attributeDescription
data-overflowPresent while the value does not fit a version 40 symbol.
data-disabledPresent when the button is disabled, while the value does not fit.

FrameQrCode.Frame

The image of the code, named "QR code: " and the value unless given a name. Holds the Pattern; CSS sizes it, and its background-color is the light colour. Renders a <svg>.

Frame data attributes
Data attributeDescription
data-overflowPresent while the value does not fit a version 40 symbol.

OverlayQrCode.Overlay

A logo or other content over the code, hidden from assistive technology. The modules under it stay drawn, so use level Q or H with it. Renders a <div>.

Overlay data attributes
Data attributeDescription
data-overflowPresent while the value does not fit a version 40 symbol.

PatternQrCode.Pattern

The dark modules, filled with currentColor. Place it inside the Frame. Renders a <path>.

Pattern data attributes
Data attributeDescription
data-overflowPresent while the value does not fit a version 40 symbol.

RootQrCode.Root

Groups all parts of the QR code and encodes the value into its symbol. Renders a <div>.

Root props
PropTypeDefault
valuerequiredThe text encoded in the symbol.string—
errorCorrectionThe error correction level requested: L, M, Q or H.QrCodeErrorCorrection'M'
boostErrorCorrectionWhether the level is raised to the highest one that fits the same version.booleantrue
quietZoneThe modules of light margin on each side, drawn inside the Frame.number4
minVersionThe smallest version used, 1 to 40.number1
labelsThe texts, in English by default: the Frame's name and the DownloadTrigger's.Partial<QrCodeLabels>—
Root data attributes
Data attributeDescription
data-overflowPresent while the value does not fit a version 40 symbol.

Shared props

Every part that renders an element takes these.

Shared props
PropType
classNameCSS class applied to the element, or a function that returns a class based on the component's state.string | ((state: State) => string | undefined)
styleStyle applied to the element, or a function that returns a style object based on the component's state.React.CSSProperties | ((state: State) => React.CSSProperties | undefined)
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State>

Keyboard and accessibility

Keyboard

QrCode has no keys of its own. The image takes no focus; the DownloadTrigger is a native button, so Enter and Space press it, and Tab passes over it while the text does not fit.

Accessibility

What the parts set
PartSetsSo that
Framean svg with role="img", named "QR code: " and the text (labels), or by aria-label or aria-labelledbya screen reader reads what the code holds, which a person who cannot scan it needs most
Framewhile the text does not fit: no role and no name, aria-hidden="true"an empty image is not announced
Patterna path with no rolethe modules are not read one by one
Overlayaria-hidden="true"the logo does not add a second name to the code
DownloadTriggera button of type button named by its text, or "Download QR code" (labels) when it has none; disabled while the text does not fitthe button says what it saves, and cannot save an empty file
Roota div with no rolethe parts are read in the order they are placed

Focus order

  1. The image is not focusable; focus passes over it.
  2. Each DownloadTrigger is one Tab stop, in the order placed, and none while the text does not fit unless focusableWhenDisabled is set.