QR Code

Pixel-perfect QR codes for any text or URL, with optional brand-coloured corners.

zweiundeins <sb-qr-code> qr code share url svg Since 2026-09-22 8.1 kB0Open in playground Edit on GitHub

Playground

Draws a QR code as a crisp SVG: every module is a pixel. It encodes with uqr (MIT), vendored unmodified from npm; vendor.json records the release it is verified against.

The code stays dark on white whatever the theme, since some scanners can't read inverted codes. Size it with CSS (inline-size), or set --sb-qr-color, --sb-qr-background and --sb-qr-accent.

Examples

Live from an input

<div data-signals="{_qr: 'https://starbase.example'}" style="display: grid; gap: 16px; justify-items: start">
  <sb-input label="Text or URL" data-bind:_qr__prop.value style="inline-size: 20rem"></sb-input>
  <sb-qr-code accent data-attr:value="$_qr" data-preserve-attr="value"></sb-qr-code>
</div>

Error correction

Higher levels survive more damage, like a logo over the middle, and need more modules.

<div style="display: flex; gap: 16px; flex-wrap: wrap">
  <sb-qr-code value="Ad astra" ecc="L" style="inline-size: 6rem"></sb-qr-code>
  <sb-qr-code value="Ad astra" ecc="H" style="inline-size: 6rem"></sb-qr-code>
</div>

Colours

<sb-qr-code value="https://github.com/zweiundeins/starbase" accent
  style="inline-size: 8rem; --sb-qr-color: #2E2780; --sb-qr-accent: #E5484D"></sb-qr-code>

From the server

Server-rendered values work as they are: <sb-qr-code value="https://example.com/invite/X7Q2">. When a stream re-renders the attribute, the code follows.

Accessibility

The SVG is an img named "QR code: " plus the value (or label). Put the link or text next to the code as well, for people who can't scan it.

Installation

Add Datastar with Rocket and the Starbase autoloader once per page, then use the tag. The autoloader imports each component the first time its tag appears, including tags added later by a Datastar morph.

<!-- Once per page: Datastar with Rocket, and the Starbase autoloader.
     It loads every <sb-…> component the first time its tag appears. -->
<script type="importmap">
  { "imports": { "datastar": "https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.4/bundles/datastar-rocket.js" } }
</script>
<script type="module" src="https://starbase.zweiundeins.gmbh/c/autoloader.js"></script>
<!-- Optional, no flash of undefined elements: class="sb-cloak" on <html>, and -->
<style>.sb-cloak :not(:defined) { visibility: hidden }</style>

<sb-qr-code value="https://data-star.dev" accent style="inline-size: 7rem"></sb-qr-code>

<!-- In production, pin today's catalog instead of the latest: the browser then
     refuses any file that changed. Add "integrity" to the import map above: the
     hashes from https://starbase.zweiundeins.gmbh/c/@0a1ad1bf98a4/importmap.json and Datastar's, below. -->
<!--
<script type="importmap">
  { "imports": { "datastar": "https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.4/bundles/datastar-rocket.js" },
    "integrity": { "https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.4/bundles/datastar-rocket.js": "sha384-vUxZojLrF1Ar3de5h7VINqhJXBgjyZS4U49pHvGa87kum6j5Xn6JRziuARNw5ELG", "…": "…from importmap.json" } }
</script>
<script type="module" src="https://starbase.zweiundeins.gmbh/c/@0a1ad1bf98a4/autoloader.js" integrity="sha384-IvSCUjEWPS+wwXunU+48x96KmyWDx/Y4LeCwCL8cWFqJ/zHmTsTOsSMrzTOcpW3D"></script>
-->

<!-- Or load just this component, pinned to this version: -->
<!-- <script type="module" src="https://starbase.zweiundeins.gmbh/c/qr-code@85832e2786cf/qr-code.js" integrity="sha384-Qbd/xqiS6itxRf3rqlDN7JdQ7lKNzKA5VzFsbYRzm1AOBGLL7/Aazne8G5HGmxcX"></script> -->

Size

Each file compressed on its own, the way it is served (gzip -9, brotli -11). Datastar and Rocket are shared by every component and not counted.

FileOriginalgzipbrotli
qr-code.js 3.2 kB1.5 kB1.3 kB
vendor/uqr.mjs 27.5 kB7.8 kB6.8 kB
Total30.7 kB9.4 kB8.1 kB

API reference

Props

AttributeTypeDefaultDescription
valuestring""Text or URL to encode.
ecc"L" | "M" | "Q" | "H""M"Error correction: L 7%, M 15%, Q 25%, H 30% of the code can be damaged or covered.
bordernumber2Quiet zone around the code, in modules (the standard asks for 4; 2 scans fine on a plain background).
accentbooleanfalseColour the three corner squares with --sb-qr-accent (default: the brand colour).
labelstring""Accessible name (default: "QR code: " and the value).