QR 코드

QR 코드 (QRCode)

텍스트를 QR 코드로 변환해 보여 주는 컴포넌트예요. URL이나 데이터를 스캔 가능한 QR 코드 이미지로 렌더링해요.

출처: 문서

본문

언제 사용하나요 (When To Use)

  • 텍스트를 QR 코드로 변환해야 할 때 사용해요.

예시 (Examples)

기본 (base)

기본 사용법이에요.

import React from 'react';
import { Input, QRCode, Space } from 'antd';

const App: React.FC = () => {
  const [text, setText] = React.useState('https://ant.design/');

  return (
    <Space vertical align="center">
      <QRCode value={text || '-'} />
      <Input
        placeholder="-"
        maxLength={60}
        value={text}
        onChange={(e) => setText(e.target.value)}
      />
    </Space>
  );
};

export default App;

아이콘과 함께 (With Icon)

아이콘이 있는 QRCode예요.

import React from 'react';
import { QRCode } from 'antd';

const App: React.FC = () => (
  <QRCode
    errorLevel="H"
    value="https://ant.design/"
    icon="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
  />
);

export default App;

다른 상태 (other status)

status 값으로 상태를 제어할 수 있어요. active, expired, loading, scanned 네 가지 값이 제공돼요.

import React from 'react';
import { Flex, QRCode } from 'antd';

const value = 'https://ant.design';

const App: React.FC = () => (
  <Flex gap="medium" wrap>
    <QRCode value={value} status="loading" />
    <QRCode value={value} status="expired" onRefresh={() => console.log('refresh')} />
    <QRCode value={value} status="scanned" />
  </Flex>
);

export default App;

커스텀 상태 렌더 (custom status render)

statusRender 값으로 상태별 QR 코드 렌더링 로직을 제어할 수 있어요.

import React from 'react';
import { CheckCircleFilled, CloseCircleFilled, ReloadOutlined } from '@ant-design/icons';
import type { QRCodeProps } from 'antd';
import { Button, Flex, QRCode, Space, Spin } from 'antd';

const value = 'https://ant.design';

const customStatusRender: QRCodeProps['statusRender'] = (info) => {
  switch (info.status) {
    case 'expired':
      return (
        <div>
          <CloseCircleFilled style={{ color: 'red' }} /> {info.locale?.expired}
          <p>
            <Button type="link" onClick={info.onRefresh}>
              <ReloadOutlined /> {info.locale?.refresh}
            </Button>
          </p>
        </div>
      );
    case 'loading':
      return (
        <Space vertical>
          <Spin />
          <p>Loading...</p>
        </Space>
      );
    case 'scanned':
      return (
        <div>
          <CheckCircleFilled style={{ color: 'green' }} /> {info.locale?.scanned}
        </div>
      );
    default:
      return null;
  }
};

const App: React.FC = () => (
  <Flex gap="medium" wrap>
    <QRCode value={value} status="loading" statusRender={customStatusRender} />
    <QRCode
      value={value}
      status="expired"
      onRefresh={() => console.log('refresh')}
      statusRender={customStatusRender}
    />
    <QRCode value={value} status="scanned" statusRender={customStatusRender} />
  </Flex>
);

export default App;

커스텀 렌더 타입 (Custom Render Type)

type으로 렌더링 결과를 커스터마이즈해요. canvas와 svg 옵션을 제공해요.

import React from 'react';
import { QRCode, Space } from 'antd';

const App: React.FC = () => (
  <Space>
    <QRCode type="canvas" value="https://ant.design/" />
    <QRCode type="svg" value="https://ant.design/" />
  </Space>
);

export default App;

커스텀 크기 (Custom Size)

크기를 직접 지정해요.

import React, { useState } from 'react';
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
import { Button, QRCode, Space } from 'antd';

const MIN_SIZE = 48;
const MAX_SIZE = 300;

const App: React.FC = () => {
  const [size, setSize] = useState<number>(160);

  const increase = () => {
    setSize((prevSize) => {
      const newSize = prevSize + 10;
      if (newSize >= MAX_SIZE) {
        return MAX_SIZE;
      }
      return newSize;
    });
  };

  const decline = () => {
    setSize((prevSize) => {
      const newSize = prevSize - 10;
      if (newSize <= MIN_SIZE) {
        return MIN_SIZE;
      }
      return newSize;
    });
  };

  return (
    <>
      <Space.Compact style={{ marginBottom: 16 }}>
        <Button onClick={decline} disabled={size <= MIN_SIZE} icon={<MinusOutlined />}>
          Smaller
        </Button>
        <Button onClick={increase} disabled={size >= MAX_SIZE} icon={<PlusOutlined />}>
          Larger
        </Button>
      </Space.Compact>
      <QRCode
        errorLevel="H"
        size={size}
        iconSize={size / 4}
        value="https://ant.design/"
        icon="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
      />
    </>
  );
};

export default App;

커스텀 색상 (Custom Color)

색을 직접 지정해요.

import React from 'react';
import { QRCode, Space, theme } from 'antd';

const { useToken } = theme;

const App: React.FC = () => {
  const { token } = useToken();
  return (
    <Space>
      <QRCode value="https://ant.design/" color={token.colorSuccessText} />
      <QRCode
        value="https://ant.design/"
        color={token.colorInfoText}
        bgColor={token.colorBgLayout}
      />
    </Space>
  );
};

export default App;

QR 코드 다운로드 (Download QRCode)

QRCode를 다운로드하는 방법이에요.

import React from 'react';
import { Button, QRCode, Segmented, Space } from 'antd';
import type { QRCodeProps } from 'antd';

function doDownload(url: string, fileName: string) {
  const a = document.createElement('a');
  a.download = fileName;
  a.href = url;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}

const downloadCanvasQRCode = () => {
  const canvas = document.getElementById('myqrcode')?.querySelector<HTMLCanvasElement>('canvas');
  if (canvas) {
    const url = canvas.toDataURL();
    doDownload(url, 'QRCode.png');
  }
};

const downloadSvgQRCode = () => {
  const svg = document.getElementById('myqrcode')?.querySelector<SVGElement>('svg');
  const svgData = new XMLSerializer().serializeToString(svg!);
  const blob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
  const url = URL.createObjectURL(blob);

  doDownload(url, 'QRCode.svg');
};

const App: React.FC = () => {
  const [renderType, setRenderType] = React.useState<QRCodeProps['type']>('canvas');
  return (
    <Space id="myqrcode" vertical>
      <Segmented options={['canvas', 'svg']} value={renderType} onChange={setRenderType} />
      <div>
        <QRCode
          type={renderType}
          value="https://ant.design/"
          bgColor="rgba(255,255,255,0.5)"
          style={{ marginBottom: 16 }}
          icon="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
        />
        <Button
          type="primary"
          onClick={renderType === 'canvas' ? downloadCanvasQRCode : downloadSvgQRCode}
        >
          Download
        </Button>
      </div>
    </Space>
  );
};

export default App;

오류 수준 (Error Level)

오류 수준을 설정해요.

import React, { useState } from 'react';
import type { QRCodeProps } from 'antd';
import { QRCode, Segmented } from 'antd';

const App: React.FC = () => {
  const [level, setLevel] = useState<QRCodeProps['errorLevel']>('L');
  return (
    <>
      <QRCode
        style={{ marginBottom: 16 }}
        errorLevel={level}
        value="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
      />
      <Segmented options={['L', 'M', 'Q', 'H']} value={level} onChange={setLevel} />
    </>
  );
};

export default App;

고급 사용법 (Advanced Usage)

Popover와 함께 사용해요.

import React from 'react';
import { Button, Popover, QRCode } from 'antd';

const App: React.FC = () => (
  <Popover content={<QRCode value="https://ant.design" bordered={false} />}>
    <Button type="primary">Hover me</Button>
  </Popover>
);

export default App;

시맨틱 DOM 스타일링 (Custom semantic dom styling)

classNames와 styles로 객체나 함수를 전달해 QRCode의 시맨틱 DOM 스타일을 커스터마이즈할 수 있어요.

import React from 'react';
import { Flex, QRCode } from 'antd';
import type { GetProp, QRCodeProps } from 'antd';
import { createStaticStyles } from 'antd-style';

const classNames = createStaticStyles(({ css }) => ({
  root: css`
    border: 1px solid #ccc;
    border-radius: 8px;
    padding: 16px;
  `,
}));

const stylesObject: QRCodeProps['styles'] = {
  root: {
    border: '2px solid #1890ff',
    borderRadius: 8,
    padding: 16,
    backgroundColor: 'rgb(24, 144, 255, 0.1)',
  },
};

const stylesFunction: QRCodeProps['styles'] = (info): GetProp<QRCodeProps, 'styles', 'Return'> => {
  if (info.props.type === 'canvas') {
    return {
      root: {
        border: '2px solid #ff4d4f',
        borderRadius: 8,
        padding: 16,
        backgroundColor: 'rgba(255, 77, 79, 0.1)',
      },
    };
  }
};

const App: React.FC = () => {
  const sharedProps: QRCodeProps = {
    value: 'https://ant.design/',
    size: 160,
    classNames,
  };

  return (
    <Flex gap="medium">
      <QRCode {...sharedProps} styles={stylesObject} />
      <QRCode
        {...sharedProps}
        type="canvas"
        icon="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
        styles={stylesFunction}
      />
    </Flex>
  );
};

export default App;

API

공통 props는 Common props를 참고해요.

이 컴포넌트는 [email protected]부터 사용할 수 있어요.

속성 (Property) 설명 (Description) 타입 (Type) 기본값 (Default) 버전 (Version) 글로벌 설정
value 스캔될 텍스트 string | string[] - string[]: 5.28.0 ×
type 렌더 타입 canvas | svg canvas 5.6.0 ×
icon 포함할 이미지 URL (이미지 링크만 지원돼요.) string - - ×
size QRCode 크기 number 160 - ×
iconSize 포함할 이미지 크기 number | { width: number; height: number } 40 5.19.0 ×
color QRCode 색 string #000 - ×
classNames 컴포넌트 내부의 각 시맨틱 구조에 대한 class를 지정해요. 객체 또는 함수를 지원해요. Record<SemanticDOM, string> | (info: { props })=> Record<SemanticDOM, string> - 6.0.0 6.0.0
bgColor QRCode 배경색 string transparent 5.5.0 ×
marginSize 조용한 영역(Quiet zone) 크기(모듈 단위). 0은 여백 없음을 의미해요. number 0 6.2.0 ×
bordered 테두리 스타일 여부 boolean true - ×
errorLevel 오류 수준 'L' | 'M' | 'Q' | 'H' M - ×
boostLevel 활성화하면 결과의 오류 수정 수준이 지정한 값보다 높아질 수 있어요. boolean true 5.28.0 ×
status QRCode 상태 active | expired | loading | scanned active scanned: 5.13.0 ×
statusRender 커스텀 상태 렌더 (info: StatusRenderInfo) => React.ReactNode - 5.20.0 ×
styles 컴포넌트 내부의 각 시맨틱 구조에 대한 인라인 스타일을 지정해요. 객체 또는 함수를 지원해요. Record<SemanticDOM, CSSProperties> | (info: { props })=> Record<SemanticDOM, CSSProperties> - 6.0.0 6.0.0

StatusRenderInfo

type StatusRenderInfo = {
  status: QRStatus;
  locale: Locale['QRCode'];
  onRefresh?: () => void;
};

시맨틱 DOM (Semantic DOM)

시맨틱 DOM 구조는 https://ant.design/components/qr-code/semantic.md 에서 확인할 수 있어요.

디자인 토큰 (Design Token)

글로벌 토큰 (Global Token)

토큰 이름 (Token Name) 설명 (Description) 타입 (Type) 기본값 (Default Value)
borderRadiusLG LG 크기 테두리 반경이에요. Card, Modal 등 큰 테두리 반경을 가진 컴포넌트에 사용돼요. number
colorSplit 구분자 색으로 사용돼요. colorBorderSecondary와 같은 색이지만 투명도를 가져요. string
colorText W3C 표준을 따르는 기본 텍스트 색이에요. 가장 어두운 중성색이기도 해요. string
colorWhite 테마에 의해 변경되지 않는 순수한 흰색 string
controlHeight Ant Design에서 버튼, 입력 상자 같은 기본 컨트롤의 높이 number
fontFamily Ant Design의 글꼴은 시스템의 기본 인터페이스 글꼴을 우선시하고, 화면 표시에 적합한 대체 글꼴 라이브러리를 제공해 플랫폼과 브라우저에 따라 가독성을 유지하며 친근하고 안정적이며 전문적인 특성을 반영해요. string
fontSize 디자인 시스템에서 가장 널리 쓰이는 글자 크기로, 여기서 텍스트 그라데이션이 파생돼요. number
lineHeight 텍스트의 줄 높이예요. number
lineType 기본 컴포넌트의 테두리 스타일 string
lineWidth 기본 컴포넌트의 테두리 두께 number
marginXS 작은 크기의 요소 여백을 제어해요. number
paddingSM 요소의 작은 패딩을 제어해요. number

FAQ

QRCode 오류 수준에 대해 (About QRCode ErrorLevel)

오류 수준(ErrorLevel)은 QR 코드가 일부 가려져도 정상적으로 스캔될 수 있는 최대 가려진 면적, 즉 오류 수정률을 의미해요.

일반적으로 QR 코드는 4가지 오류 수정 수준으로 나뉘어요. 수준 L은 약 7%, 수준 M은 약 15%, 수준 Q는 약 25%, 수준 H는 약 30%의 오류를 수정할 수 있어요. QR 코드 콘텐츠에 담긴 정보가 적을 때, 즉 value 링크가 짧을 때는 오류 수정 수준을 다르게 설정해도 생성된 이미지가 달라지지 않아요.

더 자세한 내용은 다음을 참고해요: https://www.qrcode.com/en/about/error_correction

⚠️⚠️⚠️ QR 코드를 스캔할 수 없나요?

QR 코드를 인식할 수 없다면 링크 주소가 너무 길어 픽셀이 너무 촘촘해졌기 때문일 수 있어요.

size로 QR 코드를 더 크게 설정하거나, 단축 링크 서비스로 링크를 줄여 보세요.

더 알아보기 (Learn more)