QRCode
- Stable
- WCAG 2.2 evidence
- RTL
A scannable QR code, encoded in the component with
no dependency and drawn as one SVG <path> with shape-rendering: crispEdges. Presentational and deterministic: it renders in
React Server Components, so the code is part of the HTML. Dark modules use qr/dark and the light background and quiet zone use qr/light. Both keep their colours in light and
dark mode, and forced-colours mode leaves them alone, so the code stays dark on light and keeps the 4-module quiet zone
that scanners need (never invert it). It is exposed as an image whose name is alt followed by the encoded value (WCAG
1.1.1): a QR code is not decodable by assistive technology, so the same information is given as text. Consumer duties: write alt for what the code does; show the destination as visible text next to the code where it
matters (people without a camera cannot scan it); keep enough module size for the distance it is scanned from; test with a
real scanner before shipping a logo.
import { QRCode } from "@nexera-ui/react";- 8
- examples
- 9
- props
- 4
- live controls
- 1
- platform
- 6
- WCAG criteria
- 0
- blocks use it
Try every prop. Copy the code.
Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.
import { QRCode } from "@nexera-ui/react";
<QRCode />Examples 7
The same examples as Storybook, rendered live. Open Code to copy one.
With logo
A logo in the centre: the code is encoded at level H, which restores the modules the logo covers.
import { QRCode } from "@nexera-ui/react";
const INVITE = "https://nexera.example/invite/x7Kp2Q"; // 36 bytes: version 5 at level H (37 modules, like Figma)
const Mark = () => (
<svg viewBox="0 0 10 10" fill="currentColor" aria-hidden="true">
<path d="M5 0l1.4 3.6L10 5 6.4 6.4 5 10 3.6 6.4 0 5l3.6-1.4z" />
</svg>
);
<QRCode
value={INVITE}
alt="Invitation code to join the Lahore HQ team"
variant="with-logo"
size="md"
logo={<Mark />}
/>;
Framed
A brand frame with a visible label; the label is real text, the code is one image.
import { QRCode } from "@nexera-ui/react";
const CHECK_IN = "https://nexera.example/check-in/lahore-hq/front-desk"; // 52 bytes: version 4 at level M (33 modules, like Figma)
<QRCode
value={CHECK_IN}
alt="Check-in code for the Lahore HQ front desk"
variant="framed"
size="md"
label="Scan to check in"
/>;
Error correction levels
The same value at the four error-correction levels: a higher level adds redundancy and needs more modules. Choose the lowest level that survives your use (a screen: L or M; a printed, scuffed sticker: Q or H).
import { QRCode } from "@nexera-ui/react";
const CHECK_IN = "https://nexera.example/check-in/lahore-hq/front-desk"; // 52 bytes: version 4 at level M (33 modules, like Figma)
const CHECK_IN_ALT = "Check-in code for the Lahore HQ front desk";
const levels = ["L", "M", "Q", "H"] as const;
export function ErrorCorrectionLevels() {
return (
<ul className="m-0 flex list-none flex-wrap gap-6 p-0">
{levels.map((level) => (
<li key={level} className="flex flex-col items-start gap-2">
<QRCode
value={CHECK_IN}
alt={`${CHECK_IN_ALT}, level ${level}`}
size="md"
errorCorrection={level}
/>
<span className="text-body-caption text-secondary">Level {level}</span>
</li>
))}
</ul>
);
}
With visible link
Consumer duty (WCAG 1.1.1): people without a camera cannot scan. Show where the code leads as visible text next to it. The image's own name already contains the value for screen reader users.
import { QRCode } from "@nexera-ui/react";
const CHECK_IN = "https://nexera.example/check-in/lahore-hq/front-desk"; // 52 bytes: version 4 at level M (33 modules, like Figma)
const CHECK_IN_ALT = "Check-in code for the Lahore HQ front desk";
export function WithVisibleLink() {
return (
<figure className="m-0 flex max-w-xs flex-col items-start gap-3">
<QRCode value={CHECK_IN} alt={CHECK_IN_ALT} size="md" />
<figcaption className="text-body-small text-secondary [overflow-wrap:anywhere]">
Cannot scan? Open{" "}
<a className="text-brand-text underline" href={CHECK_IN}>
{CHECK_IN}
</a>
</figcaption>
</figure>
);
}
Long value
A long value makes a dense code: this URL (185 bytes) needs version 10 (57 modules, 65 with the quiet zone), so each module is about 3.7 px at the largest size. Shorten the value or use a redirect where you can.
import { QRCode } from "@nexera-ui/react";
<QRCode
value="https://nexera.example/check-in/lahore-hq/front-desk?campaign=spring-open-day&source=poster&utm_medium=print&utm_content=a3-lobby&lang=en-GB&session=2f9d4c1e-6b7a-4d0e-9c52-0a8e1b7f3d46"
alt="Check-in code for the Lahore HQ front desk"
size="lg"
/>;
Right to left
Right-to-left: the symbol is never mirrored (a mirrored QR code does not scan); only the label's layout follows the direction.
import { QRCode } from "@nexera-ui/react";
const CHECK_IN = "https://nexera.example/check-in/lahore-hq/front-desk"; // 52 bytes: version 4 at level M (33 modules, like Figma)
const INVITE = "https://nexera.example/invite/x7Kp2Q"; // 36 bytes: version 5 at level H (37 modules, like Figma)
const Mark = () => (
<svg viewBox="0 0 10 10" fill="currentColor" aria-hidden="true">
<path d="M5 0l1.4 3.6L10 5 6.4 6.4 5 10 3.6 6.4 0 5l3.6-1.4z" />
</svg>
);
export function RightToLeft() {
return (
<div dir="rtl" lang="ar" className="flex flex-wrap items-start gap-6">
<QRCode
value={CHECK_IN}
alt="رمز تسجيل الحضور لمكتب الاستقبال"
size="md"
variant="framed"
label="امسح للتسجيل"
/>
<QRCode
value={INVITE}
alt="رمز دعوة للانضمام إلى الفريق"
size="md"
variant="with-logo"
logo={<Mark />}
/>
</div>
);
}
Narrow width
Narrow container (320 px): the largest framed code is 272 px wide and a long label wraps inside the code's width.
import { QRCode } from "@nexera-ui/react";
const CHECK_IN = "https://nexera.example/check-in/lahore-hq/front-desk"; // 52 bytes: version 4 at level M (33 modules, like Figma)
const CHECK_IN_ALT = "Check-in code for the Lahore HQ front desk";
export function NarrowWidth() {
return (
<div className="max-w-xs">
<QRCode
value={CHECK_IN}
alt={CHECK_IN_ALT}
variant="framed"
size="lg"
label="Scan this code at the front desk to check in to the Lahore HQ office today"
/>
</div>
);
}
Props 9
Press "Try it" on a card to load that prop into the playground.
9 props shown
value*NexerastringThe text or URL the code carries. It is encoded on the server, in the component, with no dependency. Numbers only, capital
letters and a few symbols, and everything else (UTF-8) use the densest of the standard's three modes. A longer value makes
a denser code (smaller modules), so keep it short: prefer a short URL that redirects. Throws a RangeError when it is empty or too long for the largest code (2953 bytes at the lowest level).
alt*NexerastringText alternative: what the code is for, for example "Check-in code for the Lahore HQ front desk" (WCAG 1.1.1). A QR code
cannot be read by assistive technology, so this is required. The encoded value is appended to it automatically, so users
who cannot scan still get the link or text.
valueTextNexerastringText that stands for value in the text alternative. Defaults to value itself. Pass the human-readable meaning only
when value is opaque (a signed URL or a token); pass "" to leave the value out.
sizeNexera"sm" | "md" | "lg"Side of the code including the quiet zone: 96, 160 or 240 px. A code with more modules needs a larger size: aim for at least 2 px per module, or phone cameras struggle.
errorCorrectionNexera"L" | "M" | "Q" | "H"How much of the code can be lost and still scan. A higher level needs more modules. with-logo covers the centre, so it
defaults to H; the other variants default to M.
classNameNexerastringExtra classes for the root, merged last so they win over the defaults.
variantNexera"plain" | "with-logo" | "framed"Presentation: plain is the code with a hairline border, with-logo puts a logo in the centre, framed
sits on a brand-coloured frame with a label.
A logo in the centre of the code.
The code on a brand-coloured frame with a label below it.
logoNexeraReactNodeOnly with variant="with-logo".
The logo mark: an SVG or image that fills its box, in brand/on-primary. The
brand-coloured frame and its light tile are drawn for you; without a mark the frame is empty. Decorative: describe the
code in alt, not the logo.
labelNexeraReactNodeOnly with variant="framed".
Visible caption below the code, in brand/on-primary. Wraps inside the
width of the code. Translate it.
* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.
Accessible by default.
Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.
WCAG 2.2 evidence
3 direct · 3 supporting- 1.1.1Non-text ContentLevel A · tested directly
- 1.3.1Info and RelationshipsLevel A · tested directly
- 1.3.2Meaningful SequenceLevel A · supporting test
- 1.4.3Contrast (Minimum)Level AA · supporting test
- 1.4.11Non-text ContrastLevel AA · supporting test
- 4.1.2Name, Role, ValueLevel A · tested directly
Fits any width.
Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.
Styling hooks
Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.
<QRCode className="shadow-sm" />Used in blocks
No block uses QRCode yet.
Related components
- AccordionItemOne collapsible section of an FAQ or settings page.
- AreaChartA stacked area chart: layers piled up over time with the title, range switch, actions and legend of the card.
- AvailabilityRowOne person's availability across a window of the day: an avatar with initials and the name, and a timeline with the busy periods drawn as bars.
- AvatarA person or organisation shown as a photo, initials or an icon.
- AvatarGroupA row of overlapping avatars with a "+N" chip for the rest.
- AvatarLabelAn avatar with a name and an optional subtitle beside it, for a person in a list, a header or a mention.
- BadgeShort status or category label: `Tone` x `Variant` x `Size`, with an optional dot, leading icon and remove button.
- BadgeGroupA pill that pairs a small badge with a short message, for an announcement or a status line.