npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

neiki-qr

v1.0.0

Published

Lightweight, dependency-free CDN-ready QR Code Generator & Scanner Web Component with dozens of QR content types, live camera scanning, and i18n support

Readme



Live version: https://neikiri.dev/qr


Overview

Neiki's QR is a Web Component written in plain JavaScript with zero dependencies — including its own from-scratch ISO/IEC 18004 QR encoder (versions 1-40, all error correction levels). Drop a single <neiki-qr> tag onto a page to get a QR Code generator with a dozen-plus ready-made content types (URL, Wi-Fi, contacts, payments, and more), or flip data-mode to scan and turn the same tag into a live camera / image QR scanner — no framework, bundler, or build step required.

<script src="https://cdn.neikiri.dev/neiki-qr/neiki-qr.min.js"></script>

<neiki-qr id="qr" data-mode="generate" type="url"></neiki-qr>
<script>
  document.getElementById('qr').setFields({ url: 'https://neikiri.dev' });
</script>

That snippet renders a scannable QR code for the given URL. Switch data-mode="scan" on the same element and it becomes a live QR reader instead.


Why Neiki's QR?

  • One script, no dependencies. The component ships as a single custom element with its own built-in QR encoder — no third-party QR library is ever loaded.
  • CDN-ready. Load it from jsDelivr or unpkg and start using <neiki-qr> immediately.
  • Generator and scanner in one tag. The same <neiki-qr> element switches its entire UI based on data-mode="generate" or data-mode="scan".
  • A dozen-plus QR content types. Text, URL, Wi-Fi, email, phone, SMS, WhatsApp, contact card (vCard), calendar event, location, SEPA payment, Czech QR payment (SPD), and Bitcoin — each with its own guided form instead of hand-built strings.
  • Live camera scanning. Uses the browser's native BarcodeDetector API for real-time detection from a camera stream or an uploaded image — no extra scanning library shipped.
  • PNG and SVG export. Download the generated code as a crisp, scalable SVG or a raster PNG.
  • Internationalized out of the box. English, Czech, German, Spanish, French, Polish, Slovak and Ukrainian translations ship with the component; add or override any language with addTranslations().
  • Accessible by design. Semantic buttons, labeled form fields, visible focus states, and reduced-motion awareness.
  • Secure by default. All dynamic content is HTML-escaped before rendering; the component never uploads or transmits scanned/generated data anywhere on its own.

Getting started

The recommended install is the single bundled script from the CDN.

<script src="https://cdn.neikiri.dev/neiki-qr/neiki-qr.min.js"></script>

Pin a specific version (recommended for production)

<script src="https://cdn.neikiri.dev/neiki-qr/1.0.0/neiki-qr.min.js"></script>

Load CSS and JS separately

<!-- Latest -->
<link rel="stylesheet" href="https://cdn.neikiri.dev/neiki-qr/neiki-qr.css">
<script src="https://cdn.neikiri.dev/neiki-qr/neiki-qr.js"></script>

<!-- Or pinned -->
<link rel="stylesheet" href="https://cdn.neikiri.dev/neiki-qr/1.0.0/neiki-qr.css">
<script src="https://cdn.neikiri.dev/neiki-qr/1.0.0/neiki-qr.js"></script>

Alternative CDN — jsDelivr

<script src="https://cdn.jsdelivr.net/npm/neiki-qr@latest/dist/neiki-qr.min.js"></script>
<!-- Pinned -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/neiki-qr.min.js"></script>

Alternative CDN — unpkg

<script src="https://unpkg.com/[email protected]/dist/neiki-qr.min.js"></script>

Package manager

npm install neiki-qr
# or
yarn add neiki-qr
# or
pnpm add neiki-qr

Self-hosted

<script src="path/to/dist/neiki-qr.min.js"></script>

The built dist/neiki-qr.min.js bundles its CSS inline — one file is all you need, no separate stylesheet to keep track of. dist/neiki-qr.css and .min.css are also published for reference (e.g. to preview the default styles or diff a customization), but the component never fetches them at runtime.


Basic usage

<neiki-qr
  id="qr"
  data-mode="generate"
  type="url"
  ecc="M"
  size="240"
  theme="auto"
  lang="en"
></neiki-qr>

<script>
  var qr = document.getElementById('qr');
  qr.setFields({ url: 'https://neikiri.dev' });
</script>

Switch to scanner mode with the same tag:

<neiki-qr data-mode="scan"></neiki-qr>

QR content types

Each type has its own set of guided form fields; call setType() to switch and setFields() to populate them (or let the user fill in the on-screen form directly).

| Type | setType() id | Fields | |------|------|--------| | Text | text | text | | URL | url | url | | Wi-Fi | wifi | ssid, password, encryption (wpa|wep|nopass), hidden | | Email | email | to, subject, body | | Phone | tel | number | | SMS | sms | number, message | | WhatsApp | whatsapp | number, message | | Contact (vCard) | vcard | firstName, lastName, phone, email, org, title, url, address | | Event | event | eventTitle, location, start, end, description | | Location | geo | lat, lon | | SEPA payment (EPC/BCD) | sepa | name, iban, bic, amount, currency, reference | | Czech QR payment (SPD) | czqr | account, amount, variableSymbol, specificSymbol, constantSymbol, message | | Bitcoin | bitcoin | address_btc, amount, label |

qr.setType('wifi');
qr.setFields({ ssid: 'HomeNet', password: 'secret123', encryption: 'wpa' });

JavaScript API

var qr = document.querySelector('neiki-qr');

// Mode
qr.setMode('generate' | 'scan');
qr.getMode();

// Generate
qr.setType('url');
qr.getType();
qr.setFields({ url: 'https://neikiri.dev' });
qr.getFields();
qr.getValue();              // the raw string encoded into the QR code
qr.toDataURL('png' | 'jpeg');
qr.download('filename', 'png' | 'svg');

// Scan
qr.startScan();
qr.stopScan();
qr.getHistory();            // array of { text, time }
qr.clearHistory();

// Config
qr.setConfig({ theme: 'dark', ecc: 'H', size: 300, lang: 'cs' });
qr.getConfig();

// i18n
qr.setLang('cs');
qr.addTranslations('en', { toolbar: { copy: 'Copy to clipboard' } });

Events

All events bubble and are composed (cross Shadow DOM boundary), with details on event.detail.

| Event | Fired when | detail | Cancelable | |-------|------------|----------|:---:| | neiki-qr:ready | The component finished its first render | { config } | | | neiki-qr:mode-change | data-mode switches between generate/scan | { mode } | | | neiki-qr:change | The generated value changes (field edit, type/ecc switch) | { type, fields, value } | | | neiki-qr:render | A new QR code matrix has been drawn | { version, eccLevel, size } | | | neiki-qr:error | Data is too long to encode, or a scan/camera error occurs | { message } | | | neiki-qr:scan-start / neiki-qr:scan-stop | The camera stream starts/stops | {} | | | neiki-qr:scan | A QR code is detected (camera or uploaded image) | { text } | ✅ |

qr.addEventListener('neiki-qr:scan', function (event) {
  event.preventDefault(); // suppress the built-in history log
  console.log('scanned:', event.detail.text);
});

Attributes

| Attribute | Values | Default | Description | |-----------|--------|---------|--------------| | data-mode | generate, scan | generate | Whether the component shows the generator or the scanner UI | | type | see QR content types | text | Active QR content type (generate mode) | | ecc | L, M, Q, H | M | Error correction level | | size | number (px) | 240 | Rendered QR code size | | theme | light, dark, auto | auto | Visual theme | | lang | en, cs, de, es, fr, pl, sk, uk | en | Interface language |


CSS variables

All variables use the --nqr-* prefix and can be overridden per instance or globally:

neiki-qr {
  --nqr-radius: 12px;
  --nqr-accent: #7c3aed;
  --nqr-bg: #ffffff;
  --nqr-color: #1f2328;
}

| Variable | Purpose | |----------|---------| | --nqr-radius / --nqr-radius-sm | Container / inner element border radius | | --nqr-gap | Spacing between toolbar controls | | --nqr-font-size | Base font size | | --nqr-transition | Transition timing | | --nqr-shadow | Preview card box-shadow | | --nqr-bg / --nqr-bg-subtle / --nqr-bg-hover | Background layers | | --nqr-color / --nqr-color-muted | Text colors | | --nqr-border | Border color | | --nqr-accent / --nqr-accent-contrast | Accent color and its contrasting text/icon color | | --nqr-focus-ring | Keyboard focus ring color | | --nqr-danger / --nqr-success | Status colors |


Internationalization

Eight languages ship built in: English (en), Czech (cs), German (de), Spanish (es), French (fr), Polish (pl), Slovak (sk) and Ukrainian (uk).

<neiki-qr lang="cs"></neiki-qr>
qr.setLang('uk');

Add a new language, or override strings in an existing one, with addTranslations():

qr.addTranslations('it', {
  mode: { generate: 'Genera', scan: 'Scansiona' },
  toolbar: { copy: 'Copia contenuto' }
});
qr.setLang('it');

Only the keys you pass are merged in — omitted keys fall back to English.


Accessibility

  • Every interactive control (mode switch, form fields, download/copy buttons) is a real <button>, <select>, <input>, or <label> — no div-as-button anti-patterns.
  • Visible :focus-visible outlines on every interactive element.
  • prefers-reduced-motion: reduce disables transitions.
  • Colors default to sufficient contrast in both light and dark themes.

Security

  • The component renders inside a Shadow DOM, isolating its markup and styles from the host page.
  • All dynamic text (form input, scan results, translations) is HTML-escaped before being rendered.
  • The QR encoder and camera-frame decoding run entirely client-side; the component makes no network requests of its own and does not transmit generated or scanned data anywhere.
  • Camera access uses the standard getUserMedia permission prompt; the stream is stopped and released as soon as scanning stops or the component disconnects.

See SECURITY.md for the full policy and how to report vulnerabilities.


Demo

Open demo/index.html in a browser (or serve the repo locally) to see the generator across every content type, live camera scanning, themes, i18n, and the full JavaScript API in action.


Build / minify

npm run build

Runs minify.py, which reads src/neiki-qr.js and src/neiki-qr.css and produces:

dist/neiki-qr.js       # CSS embedded inline, unminified
dist/neiki-qr.min.js   # CSS embedded inline, minified (recommended)
dist/neiki-qr.css      # standalone copy, for reference
dist/neiki-qr.min.css  # standalone copy, for reference

The CSS is baked directly into both JavaScript bundles at build time — loading either dist script is enough on its own, no separate stylesheet request required. JS minification uses Terser via npx when available, falling back to an unminified copy otherwise.

npm test

Runs node --check against the source file as a syntax sanity check.


Browser support

Neiki's QR uses Custom Elements v1, Shadow DOM, and standard DOM APIs, and targets current versions of modern browsers. QR generation works everywhere Custom Elements and Canvas are supported. Live camera scanning additionally requires the BarcodeDetector API (Chrome, Edge, Opera, Android WebView); browsers without it show a friendly fallback message instead of the camera view.

| Browser | Generate | Scan | |---------|:---:|:---:| | Chrome | ✅ | ✅ | | Edge | ✅ | ✅ | | Opera | ✅ | ✅ | | Firefox | ✅ | ⚠️ fallback message | | Safari | ✅ | ⚠️ fallback message |

Internet Explorer is not supported.


Contributing

Contributions are welcome. Please review CONTRIBUTING.md and the CODE_OF_CONDUCT.md before opening an issue or pull request. Security-related reports should follow SECURITY.md.

The component source lives in src/ (neiki-qr.js, neiki-qr.css); the distributable builds are in dist/.


License

Released under the MIT License. See the LICENSE file for details.