Qr Code
A shadcn-style qr code component built with Ark UI primitives.
import { QrCode, QrCodeFrame, QrCodePattern } from "@/components/ui/qr-code";
const QrCodeBasic = () => (
<QrCode defaultValue="https://ark-ui.com">
<QrCodeFrame>
<QrCodePattern />
</QrCodeFrame>
</QrCode>
);
export default QrCodeBasic;
Installation
npx shadcn@latest add @ark-cn/qr-codeInstall the dependency required by this primitive:
npm install @ark-ui/reactCopy the component source into your app:
TSXcomponents/ui/qr-code.tsx
"use client";
import {
QrCode as QrCodePrimitive,
useQrCode,
useQrCodeContext,
} from "@ark-ui/react/qr-code";
import type { CSSProperties } from "react";
import { cn } from "@/lib/utils";
export type QrCodeOwnProps = {
/** Square display size in CSS pixels. Default 100. Ignored when both `width` and `height` are set. */
size?: number;
/** Display width in CSS pixels. Use with `height` for a non-square frame. */
width?: number;
/** Display height in CSS pixels. Use with `width`. */
height?: number;
};
const qrCodeLayoutStyle = ({
size = 100,
width,
height,
}: QrCodeOwnProps): CSSProperties => {
if (width !== undefined && height !== undefined) {
return {
"--qr-code-width": `${width}px`,
"--qr-code-height": `${height}px`,
"--qr-code-overlay-size": `calc(min(${width}px, ${height}px) / 3)`,
} as CSSProperties;
}
return {
"--qr-code-size": `${size}px`,
"--qr-code-overlay-size": "calc(var(--qr-code-size) / 3)",
} as CSSProperties;
};
export type QrCodeProps = QrCodePrimitive.RootProps & QrCodeOwnProps;
export const QrCode = ({
className,
size,
width,
height,
style,
...props
}: QrCodeProps) => (
<QrCodePrimitive.Root
className={cn(
"relative flex w-fit flex-col gap-2 text-foreground",
className,
)}
data-slot="qr-code"
style={{ ...qrCodeLayoutStyle({ size, width, height }), ...style }}
{...props}
/>
);
export type QrCodeFrameProps = QrCodePrimitive.FrameProps;
export const QrCodeFrame = ({ className, ...props }: QrCodeFrameProps) => (
<QrCodePrimitive.Frame
className={cn(
"block h-(--qr-code-height,var(--qr-code-size)) w-(--qr-code-width,var(--qr-code-size)) max-w-full shrink-0 fill-current text-foreground",
className,
)}
data-slot="qr-code-frame"
{...props}
/>
);
export type QrCodePatternProps = QrCodePrimitive.PatternProps;
export const QrCodePattern = ({ className, ...props }: QrCodePatternProps) => (
<QrCodePrimitive.Pattern
className={cn("fill-inherit", className)}
data-slot="qr-code-pattern"
{...props}
/>
);
export type QrCodeOverlayProps = QrCodePrimitive.OverlayProps;
export const QrCodeOverlay = ({ className, ...props }: QrCodeOverlayProps) => (
<QrCodePrimitive.Overlay
className={cn(
"flex size-(--qr-code-overlay-size) items-center justify-center rounded-md bg-popover p-1",
"[&_img]:size-full [&_img]:object-contain [&_svg]:size-full [&_svg]:object-contain",
className,
)}
data-slot="qr-code-overlay"
{...props}
/>
);
export type QrCodeDownloadTriggerProps = QrCodePrimitive.DownloadTriggerProps;
export const QrCodeDownloadTrigger = ({
className,
...props
}: QrCodeDownloadTriggerProps) => (
<QrCodePrimitive.DownloadTrigger
className={cn(
"inline-flex h-8 min-w-8 shrink-0 items-center justify-center rounded-md border-0 bg-muted px-3 font-medium text-foreground text-sm transition-[background-color,color] hover:bg-foreground hover:text-background",
className,
)}
data-slot="qr-code-download-trigger"
{...props}
/>
);
export type QrCodeRootProviderProps = QrCodePrimitive.RootProviderProps &
QrCodeOwnProps;
export const QrCodeRootProvider = ({
className,
size,
width,
height,
style,
...props
}: QrCodeRootProviderProps) => (
<QrCodePrimitive.RootProvider
className={cn(
"relative flex w-fit flex-col gap-2 text-foreground",
className,
)}
data-slot="qr-code-provider"
style={{ ...qrCodeLayoutStyle({ size, width, height }), ...style }}
{...props}
/>
);
export const QrCodeContext = QrCodePrimitive.Context;
export type { QrCodeGenerateOptions } from "@ark-ui/react/qr-code";
export { useQrCode, useQrCodeContext };
Update import aliases to match your project setup.
Usage
import * as QrCode from "@/components/ui/qr-code"Read exported parts in src/components/ui/qr-code.tsx and compose the primitive according to the Ark UI pattern for this component.
Examples
Basic
import { QrCode, QrCodeFrame, QrCodePattern } from "@/components/ui/qr-code";
const QrCodeBasic = () => (
<QrCode defaultValue="https://ark-ui.com">
<QrCodeFrame>
<QrCodePattern />
</QrCodeFrame>
</QrCode>
);
export default QrCodeBasic;
Controlled
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { QrCode, QrCodeFrame, QrCodePattern } from "@/components/ui/qr-code";
const QrCodeControlled = () => {
const [value, setValue] = useState("https://ark-ui.com");
return (
<div className="flex flex-col gap-3">
<QrCode
onValueChange={(details) => {
setValue(details.value);
}}
value={value}
>
<QrCodeFrame>
<QrCodePattern />
</QrCodeFrame>
</QrCode>
<Button
onClick={() => {
setValue("https://react.dev");
}}
type="button"
variant="outline"
>
Encode react.dev
</Button>
</div>
);
};
export default QrCodeControlled;
Download
import {
QrCode,
QrCodeDownloadTrigger,
QrCodeFrame,
QrCodePattern,
} from "@/components/ui/qr-code";
const QrCodeDownload = () => (
<QrCode defaultValue="https://ark-ui.com">
<QrCodeFrame>
<QrCodePattern />
</QrCodeFrame>
<QrCodeDownloadTrigger fileName="qr-code.png" mimeType="image/png">
Download PNG
</QrCodeDownloadTrigger>
</QrCode>
);
export default QrCodeDownload;
Error correction
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { QrCode, QrCodeFrame, QrCodePattern } from "@/components/ui/qr-code";
const qrEccLevels = ["L", "M", "Q", "H"] as const;
type QrCodeEccLevel = (typeof qrEccLevels)[number];
const QrCodeErrorCorrection = () => {
const [ecc, setEcc] = useState<QrCodeEccLevel>("L");
return (
<div className="flex flex-col gap-3">
<div className="flex flex-wrap gap-2">
{qrEccLevels.map((level) => (
<Button
key={level}
onClick={() => {
setEcc(level);
}}
size="sm"
type="button"
variant={ecc === level ? "default" : "outline"}
>
{level}
</Button>
))}
</div>
<QrCode defaultValue="https://ark-ui.com" encoding={{ ecc }}>
<QrCodeFrame>
<QrCodePattern />
</QrCodeFrame>
</QrCode>
</div>
);
};
export default QrCodeErrorCorrection;
Fill
import { QrCode, QrCodeFrame, QrCodePattern } from "@/components/ui/qr-code";
const QrCodeFill = () => (
<div className="flex flex-wrap gap-6">
{["#5417D7", "#EC5D5E"].map((fill) => (
<QrCode defaultValue="https://ark-ui.com" key={fill}>
<QrCodeFrame className="text-foreground" style={{ fill }}>
<QrCodePattern />
</QrCodeFrame>
</QrCode>
))}
</div>
);
export default QrCodeFill;
Overlay
import {
QrCode,
QrCodeFrame,
QrCodeOverlay,
QrCodePattern,
} from "@/components/ui/qr-code";
const QrCodeOverlayExample = () => (
<QrCode defaultValue="https://ark-ui.com" encoding={{ ecc: "H" }}>
<QrCodeFrame>
<QrCodePattern />
</QrCodeFrame>
<QrCodeOverlay>
<img
alt="Ark UI"
height={48}
src="https://ark-ui.com/icon-192.png"
width={48}
/>
</QrCodeOverlay>
</QrCode>
);
export default QrCodeOverlayExample;
Root provider
import { Button } from "@/components/ui/button";
import {
QrCodeFrame,
QrCodePattern,
QrCodeRootProvider,
useQrCode,
} from "@/components/ui/qr-code";
const QrCodeRootProviderExample = () => {
const store = useQrCode({ defaultValue: "https://ark-ui.com" });
return (
<div className="flex max-w-md flex-col gap-3">
<QrCodeRootProvider value={store}>
<QrCodeFrame>
<QrCodePattern />
</QrCodeFrame>
</QrCodeRootProvider>
<output className="text-muted-foreground text-xs">
<span className="text-foreground">Current value:</span>{" "}
<span className="font-mono text-foreground">{store.value}</span>
</output>
<div className="flex flex-wrap gap-2">
<Button
onClick={() => {
store.setValue("https://react.dev");
}}
size="sm"
type="button"
variant="outline"
>
react.dev
</Button>
<Button
onClick={() => {
store.setValue("https://ark-ui.com");
}}
size="sm"
type="button"
variant="secondary"
>
ark-ui.com
</Button>
</div>
</div>
);
};
export default QrCodeRootProviderExample;
Context
Value length: 18
import {
QrCode,
QrCodeContext,
QrCodeFrame,
QrCodePattern,
} from "@/components/ui/qr-code";
const QrCodeContextExample = () => (
<QrCode defaultValue="https://ark-ui.com">
<QrCodeContext>
{(context) => (
<p className="text-muted-foreground text-xs">
Value length:{" "}
<span className="font-medium tabular-nums text-foreground">
{context.value.length}
</span>
</p>
)}
</QrCodeContext>
<QrCodeFrame>
<QrCodePattern />
</QrCodeFrame>
</QrCode>
);
export default QrCodeContextExample;
API reference
This component mirrors the upstream Ark UI primitive.
See the ARK UI documentation for the full API.
