자주 묻는 질문

자주 묻는 질문 (FAQ)

Ant Design과 antd에 대해 자주 묻는 질문을 모았어요. 커뮤니티에서 질문하거나 새 이슈를 만들기 전에 먼저 살펴보세요. 흔한 GitHub 이슈에 대해서는 FAQ issues 라벨도 함께 관리하고 있어요.

출처: 문서

본문


antd의 제어 컴포넌트에서 undefined와 null의 차이가 있나요?

네. antd는 undefined를 비제어(uncontrolled)로, null을 제어(controlled) 컴포넌트로 취급해요. 즉 null은 '빈 값'을 뜻해요.

입력 요소로서 React는 undefined와 null을 모두 비제어로 취급해요. value가 유효한 값에서 undefined나 null로 바뀌면 컴포넌트는 더 이상 제어되지 않아 예상치 못한 상황이 생길 수 있어요.

하지만 antd에서는 undefined를 비제어로, null을 제어 컴포넌트의 명시적 빈 값으로 취급해요. 이는 value가 비원시(non-primitive)일 때 value를 지우는 것 같은 케이스(e.g. allowClear)를 다루기 위해서예요. 유효한 value로 컴포넌트를 제어해야 한다면 그냥 value를 null로 설정하면 돼요.

참고: Select류 컴포넌트의 options에서는 option의 value로 undefined와 null을 사용하지 않는 것을 강력히 권장해요. option의 유효한 value로는 string | number를 사용하세요.

어떤 빈 콘텐츠에 대해 여전히 DOM 노드가 렌더링되는 이유는? {#react-renderable}

antd는 @rc-component/util의 isReactRenderable를 사용해 콘텐츠 래퍼 DOM을 만들지 판단해요. 이는 호환성 지향의 콘텐츠 존재 체크로 설계됐지, 유효한 React 노드에 대한 검증기는 아니에요. React가 결국 가시적 콘텐츠를 만들지 재귀적으로 예측하지도 않아요.

isReactRenderable은 오직 null, undefined, false, 빈 문자열 ''만 콘텐츠가 없는 것으로 취급해요. 다른 모든 값은 콘텐츠로 취급되죠. 그래서 래퍼 DOM을 렌더링할지 제어할 때:

값 isReactRenderable 결과
null, undefined, false, '' false 래퍼 DOM도 콘텐츠도 렌더링되지 않음
true true 래퍼 DOM은 생성되지만, true에 대해 React는 텍스트 콘텐츠를 렌더링하지 않음
0 true 래퍼 DOM이 생성되고 0은 정상적으로 렌더링됨
비어 있지 않은 문자열, 다른 숫자, React 요소 등 true 래퍼 DOM이 생성되고 React가 콘텐츠를 처리함

여기서 false는 명시적 '콘텐츠 없음' 표시로 취급되고, true는 콘텐츠가 제공됐다는 뜻이에요. true 자체는 텍스트 노드를 만들지 않지만 래퍼 DOM은 여전히 생성돼요. 마찬가지로 빈 배열, 빈 Fragment, 결국 null을 반환하는 React 요소도 체크를 통과해요. 숫자 0은 빈 콘텐츠로 오인되지 않고 정상적으로 렌더링돼요.

사이트에 문서화되지 않은 내부 API를 사용해도 되나요?

권장하지 않아요. 내부 API는 향후 버전과 호환성이 보장되지 않아요. 어떤 버전에서 제거되거나 바뀔 수 있어요. 꼭 사용해야 한다면 새 버전으로 업그레이드할 때 그 API가 여전히 유효한지 확인하거나, 사용할 버전을 고정(lock)해야 해요.

API 요청이 엄격하게 논의되어야 하는 이유는?

API를 추가할 때 우리는 신중해요. 일부 API는 충분히 추상적이지 않아 역사적 부채(historical debt)가 될 수 있거든요. 예를 들어 상호작용 방식을 바꿔야 할 필요가 생기면, 이런 나쁜 추상화가 breaking change를 일으킬 수 있어요. 이런 문제를 피하기 위해 새 기능은 먼저 HOC를 통해 구현하는 것을 권장해요.

Select Dropdown DatePicker TimePicker Popover Popconfirm이 그 안의 다른 팝업 컴포넌트를 클릭하면 사라져요. 어떻게 해결하나요?

v3.11.x부터 수정된 오래된 버그예요. 구버전을 사용한다면 <Select getPopupContainer={trigger => trigger.parentElement}>로 Popover 안에 컴포넌트를 렌더링할 수 있어요. (또는 다른 getXxxxContainer props)

https://ant.design/components/select/#Select-props

관련 이슈: #3487 #3438

Select Dropdown DatePicker TimePicker Popover Popconfirm이 페이지와 함께 스크롤되지 않게 하려면?

<Select getPopupContainer={trigger => trigger.parentElement}> (API 참조)를 사용해 스크롤 영역 안에 컴포넌트를 렌더링하세요. 애플리케이션에서 전역으로 설정해야 한다면 <ConfigProvider getPopupContainer={trigger => trigger.parentElement}> (API 참조)를 시도해 보세요.

그리고 parentElement가 position: relative 또는 position: absolute인지 확인하세요.

관련 이슈: #3487 #3438

Ant Design의 기본 테마를 어떻게 수정하나요?

참고: customize-theme.

컴포넌트의 스타일을 오버라이드할 수는 있지만, 권장하지 않아요. antd는 단순한 React 컴포넌트 모음이 아니라 하나의 디자인 스펙이기도 하거든요.

버전을 업데이트할 때 breaking change를 피하려면?

antd는 minor & patch 버전에서 breaking change를 피해요. 다음은 안전하게 해도 되는 것들이에요.

  • 공식 데모 사용
  • FAQ 제안. FAQ 이슈로 표시된 CodeSandbox 샘플 포함

그리고 피해야 할 것들:

  • 버그를 기능으로 만들기. 다른 경우에 깨질 수 있어요 (예: Tabs children으로 div 사용)
  • 일반 API로 구현할 수 있는 것을 매직 코드로 구현하기

Moment.js 같은 다른 날짜·시간 라이브러리를 어떻게 사용하나요?

커스텀 날짜 라이브러리 사용을 참고하세요.

defaultValue를 동적으로 바꿔도 동작하지 않아요.

Input/Select(등)의 defaultXxxx(예: defaultValue)는 첫 렌더링 때만 동작해요. 이는 React의 스펙이에요. React 문서를 읽어 보세요.

props를 가변(mutable)하게 수정하면 컴포넌트가 업데이트되지 않는 이유는?

antd는 성능 최적화를 위해 props를 얕은 비교(shallow compare)해요. 상태를 업데이트할 때는 항상 새 객체를 전달해야 해요. React 문서를 참고하세요.

antd에 중국 미러가 있나요?

네, https://ant-design.antgroup.com 을 방문하면 돼요.

제품/버전 URL
Ant Design 5.x https://5x-ant-design.antgroup.com
Ant Design 4.x https://4x-ant-design.antgroup.com
Ant Design Mobile https://ant-design-mobile.antgroup.com/zh
Ant Design Mini https://ant-design-mini.antgroup.com
Ant Design Charts https://ant-design-charts.antgroup.com

Input/Select(등) 컴포넌트의 value를 설정한 후, 사용자 동작으로 값을 바꿀 수 없어요.

onChange로 value를 변경해 보세요. React 문서를 읽어 보세요.

한 줄에 배치했을 때 컴포넌트가 세로로 정렬되지 않아요.

Space 컴포넌트로 정렬해 보세요.

타사 SVG 아이콘에 margin-block-end가 있는 이유는? {#faq-icon-margin-block-end}

Breadcrumb, Collapse, Segmented, Tabs, Tag 같은 컴포넌트는 해당 아이콘 슬롯에 직접 렌더링된 SVG에 display: inline-block, vertical-align: middle, margin-block-end: 0.2em을 적용해 텍스트와의 시각적 정렬을 조정해요.

인라인 레이아웃에서 SVG는 텍스트 기준선(baseline)이 없어서 기본적으로 아래 가장자리가 기준선 정렬에 참여해요. 그래서 텍스트 옆에서 너무 높게 보일 수 있어요. display: inline-block은 아이콘을 인라인 흐름에 유지하고, vertical-align: middle은 margin box의 중심을 부모 기준선 + x-height(소문자 x의 높이) 절반에 정렬해 아이콘 높이와 무관하게 정렬되게 해요.

그런데 x-height의 중심은 대문자의 중심보다 보통 더 낮아서, 약간 위쪽의 광학적 보정이 필요해요. margin-block-end: 0.2em은 아이콘 아래에 여백을 추가해요. margin box가 중앙에 오면 아이콘 자체는 약 0.1em 위로 올라가 공통 폰트에서 대문자 중심에 더 가까워져요. 0.2em 값은 공통 폰트의 cap height와 x-height의 차이를 근사하며, em을 사용하면 보정이 폰트 크기에 맞춰 비례해요.

이 스타일은 직접 렌더링된 SVG를 대상으로 해요. @ant-design/icons의 아이콘은 SVG를 별도 컨테이너로 감싸고 자체 정렬 스타일을 사용해요. 다른 폰트, 내부 아이콘 공백, 아이콘 자체의 vertical-align이 결과에 영향을 줄 수 있어요. 아이콘이 이미 자체 정렬을 처리하거나, 아이콘만 단독으로 쓰는 경우 텍스트 정렬 보정이 필요 없다면, margin-block-end: 0으로 해당 SVG를 로컬로 오버라이드하고 필요에 따라 스타일을 조정하면 돼요.

antd가 내 전역 스타일을 덮어써요

네, antd는 완전한 백그라운드 애플리케이션 개발을 돕도록 설계됐어요. 그래서 스타일링 편의를 위해 일부 전역 스타일을 덮어쓰며, 현재 이들은 제거하거나 변경할 수 없어요. 자세한 내용은 https://github.com/ant-design/ant-design/issues/4331 .

대안으로 전역 스타일 수정을 피하는 방법의 지침을 따르세요.

중국 본토에서 antd와 antd 의존성을 설치하지 못해요.

가능한 해결책으로 npm mirror china와 cnpm을 시도해 보세요.

package.json의 dependencies.antd를 git 저장소로 설정했는데 동작하지 않아요.

antd를 npm이나 yarn으로 설치하세요.

message와 notification은 소문자인데 다른 컴포넌트는 대문자예요. 오타인가요?

아니에요. message는 함수이지 React 컴포넌트가 아니기 때문에 소문자인 게 오타가 아니에요.

antd가 모바일에서 잘 동작하지 않아요.

antd는 모바일에서 잘 동작하도록 최적화되지 않았으니, Ant Design Mobile을 가능한 해결책으로 확인해 보세요. 모바일용으로 설계된 react-component 저장소 중 'm-' 'rn-'으로 시작하는 것들도 시도해 볼 수 있어요.

antd가 'React'처럼 독립 파일을 제공하나요?

네, script tag로 antd를 import할 수 있어요. 다만 npm으로 import하는 것이 단순하고 유지보수하기 쉬워 권장해요.

antd의 컴포넌트를 어떻게 확장하나요?

antd에 포함되지 않아야 할 기능이 필요하다면, HOC로 antd 컴포넌트를 확장해 보세요. 더 보기

antd는 새 컴포넌트에 대한 수요를 엄격하게 논의해 API가 오염되고 역사적 부채가 되는 것을 막아요. 그리고 API에 원자적(atomic)인 능력을 제공해 개발자가 필요한 기능을 더 유연하게 커스터마이즈할 수 있게 하는 쪽에 더 가까워요.

export되지 않은 정의를 어떻게 가져오나요?

antd는 기본 컴포넌트 정의를 노출해요. 노출되지 않은 props는 antd가 제공하는 유틸리티 타입으로 얻을 수 있어요. 예:

import type { Checkbox, CheckboxProps, GetProp, GetProps, GetRef, Input } from 'antd';

// Get Props
type CheckboxGroupProps = GetProps<typeof Checkbox.Group>;

// Get Prop
type CheckboxValue = GetProp<CheckboxProps, 'value'>;

// Get Ref
type InputRef = GetRef<typeof Input>;

날짜 관련 컴포넌트 locale이 동작하지 않아요?

dayjs locale을 올바르게 import했는지 확인하세요.

import dayjs from 'dayjs';

import 'dayjs/locale/zh-cn';

dayjs.locale('zh-cn');

dayjs가 두 버전으로 설치되어 있는지 확인해 보세요.

npm ls dayjs

프로젝트의 dayjs 버전이 antd의 dayjs와 맞지 않으면 locale이 동작하지 않는 문제가 생길 수 있어요.

CSP(Content Security Policy)를 사용할 때 동적 스타일을 어떻게 고치나요?

ConfigProvider로 nonce를 설정할 수 있어요.

DatePicker/RangePicker에 mode를 설정하면 더 이상 연도나 월을 선택할 수 없는 이유는?

실제 개발에서는 YearPicker, MonthRangePicker, WeekRangePicker가 필요할 수 있어요. 이를 구현하려고 DatePicker/RangePicker에 mode를 추가했는데, DatePicker/RangePicker는 선택도 안 되고 패널도 닫히지 않게 됐죠.

설명처럼, <DatePicker mode="year" />는 YearPicker와 같지 않고, <RangePicker mode="month" />도 MonthRangePicker와 같지 않아요. mode 속성은 antd 3.0에서 DatePicker에 시간 피커 패널을 표시하는 것을 지원하기 위해 추가됐어요. mode는 표시되는 패널만 제어하며 DatePicker/RangePicker의 원래 날짜 선택 동작을 바꾸지 않아요 (예: mode가 무엇이든 DatePicker에서 선택을 끝내려면 여전히 날짜 셀을 클릭해야 해요).

마찬가지로 disabledDate는 <DatePicker mode="year/month" />의 연도/월 패널에서는 동작할 수 없고, 날짜 패널의 셀에서만 동작해요.

:::success{title=해결 방법} 이 글이나 이 글을 참고해 mode와 onPanelChange를 사용해 필요한 YearPicker나 MonthRangePicker를 캡슐화할 수 있어요.

또는 더 많은 XxxPickers를 추가한 [email protected]으로 업그레이드하면, disabledDate도 그 피커들에서 동작해요. :::

ConfigProvider에 prefixCls를 설정하면 message/notification/Modal.confirm 스타일이 사라져요?

message/notification/Modal.confirm 같은 정적 메서드는 <Button />과 같은 렌더 트리를 사용하지 않아요. ReactDOM.render가 만든 독립 DOM 노드에 렌더링되므로 ConfigProvider의 React context에 접근할 수 없어요. 두 가지 해결책을 고려해 보세요.

  1. 기존 사용처를 message.useMessage, notification.useNotification, Modal.useModal로 대체해요.

  2. App.useApp으로 message/notification/modal 인스턴스를 얻어요.

ref로 컴포넌트 내부 props나 state를 사용하면 안 되는 이유는?

ref로는 공식 문서의 API에만 접근해야 해요. 내부 props나 state에 직접 접근하는 것은 권장하지 않아요. 현재 버전과 강하게 결합되는 코드가 되기 때문이에요. Hooks 버전으로의 리팩터링 같은 어떤 리팩터링이든 내부 props나 state를 삭제하거나 이름을 바꾸거나, 내부 노드 생성자를 조정하면 코드가 깨질 수 있어요.

pop 컴포넌트를 open prop과 정렬해야 하는 이유는?

역사적 이유로 pop 컴포넌트들의 표시 이름이 통일되지 않아 open과 visible이 모두 사용됐어요. 이는 non-tsx 사용자가 개발 중 겪는 기억 부담을 만듭니다. 또한 기능을 추가할 때 어떤 이름을 고를지에 대한 모호함을 만들었어요. 그래서 속성 이름을 통일하려는 것이고, 기존 visible은 여전히 사용할 수 있으며 하위 호환되지만 v5부터 문서에서 제거할 거예요.

구버전 브라우저를 지원하지 않는 :where 셀렉터를 사용하는 동적 스타일

동적 테마 문서의 구버전 브라우저 호환 부분을 참고하세요.

CSS-in-JS css 우선순위가 tailwindcss와 충돌해요?

위와 같아요. antd css 우선순위를 조정해 오버라이드할 수 있어요. 관련 이슈: #38794

CSS-in-JS를 shadow DOM에서 동작하게 하려면?

Shadow Dom 사용법 문서를 참고하세요.

모션을 비활성화하려면?

SeedToken으로 설정해요.

import { ConfigProvider } from 'antd';

<ConfigProvider theme={{ token: { motion: false } }}>
  <App />
</ConfigProvider>;

SSR은 어떻게 지원하나요?

동적 테마 문서의 SSR 부분을 참고하세요.

V5에서 colorPrimary와 colorInfo, colorLink의 관계는?

Ant Design Token 시스템에서 colorPrimary와 colorInfo는 모두 Seed Token이라 서로 독립적이에요. colorLink는 Alias Token으로 기본적으로 colorInfo를 상속하며 colorPrimary와는 독립이에요.

Ant Design을 올바르게 표기하는 방법은?

표기 용도 발음
✅ Ant Design 대문자+공백, 디자인 언어를 지칭 -
✅ antd 전부 소문자, React UI 라이브러리를 지칭
✅ ant.design ant.design 웹사이트 URL -

전형적인 잘못된 예:

  • ❌ AntD
  • ❌ antD
  • ❌ Antd
  • ❌ ant design
  • ❌ AntDesign
  • ❌ antdesign
  • ❌ Antdesign

PayPal이나 Alipay 같은 기부 채널이나 웹사이트가 있나요?

https://opencollective.com/ant-design

Form의 setFieldsValue 메서드를 객체 타입에 null이 포함되면 오류가 나요

폼 컴포넌트의 폼 인스턴스에서 setFieldsValue 메서드로 폼 값을 설정하려고 할 때, 전달한 객체에 null 타입이 포함되어 있으면:

// This is not real world code, just for explain
import { Form } from 'antd';

type Test = {
  value: string[] | null;
};

export default () => {
  const [form] = Form.useForm<Test>();

  form.setFieldsValue({
    value: null, // Error: Type "null" cannot be assigned to type "string[] | undefined".
  });
};

위 오류가 발생하면 현재 프로젝트 tsconfig.json에 다음 설정이 있는지 확인하세요.

{
  "strictNullChecks": true
}

strictNullChecks가 true로 설정되면 위 문제가 발생해요. 이 설정이 필요 없다고 판단되면 (필요 여부는 strictNullChecks로 판단) false로 바꿔 엄격 검사를 끌 수 있어요. 하지만 이 기능이 필요하다면 타입 정의할 때 null 대신 다른 타입을 사용해 이 상황을 피할 수 있어요.

브라우저 줌에서 마주치는 정밀도 문제를 antd가 처리하지 않는 이유는?

브라우저마다 줌할 때 렌더링 동작이 달라요. 한 브라우저의 정밀도 문제를 고치면 다른 브라우저에서 문제가 생기는 경우가 많아요. 게다가 줌 관련 정밀도 문제는 보통 극단적인 줌 수준에서만 발생하며 일반 사용에서는 드물어요. 렌더링 불일치는 브라우저가 줌 중 요소를 계산하고 렌더링하는 방식에서 생기는데, 서브픽셀 렌더링, 반올림 차이, 레이아웃 재계산을 포함해요. 이를 해결하려면 상당한 양의 브라우저별 코드가 필요하고, 성능과 유지보수성에 부정적 영향을 주며 브라우저 자체의 반복 업데이트에 의해 깨질 수도 있어요.

Next.js의 App Router를 사용할 때 antd 컴포넌트가 오류를 보고했어요

Next.js의 App Router를 사용할 때 Select.Option, Form.Item, Typography.Title 같은 일부 antd 컴포넌트의 하위 컴포넌트를 사용하면 다음 오류가 나올 수 있어요.

Error: Cannot access .Option on the server. You cannot dot into a client module from a server component. You can only pass the imported name through.

현재 이 문제는 Next.js의 공식 해결책을 기다리고 있어요. App Router로 페이지에서 하위 컴포넌트를 사용해야 한다면 지금으로서는 두 가지 해결 방법이 있어요.

  • 필요한 하위 컴포넌트를 추출해 다시 export하는 래퍼 컴포넌트를 만들어요. Typography 컴포넌트를 예로 들면 래퍼 컴포넌트는 대략 이렇게 생겼어요.
'use client';

import React from 'react';
import { Typography as OriginTypography } from 'antd';
import type { LinkProps } from 'antd/es/typography/Link';
import type { ParagraphProps } from 'antd/es/typography/Paragraph';
import type { TextProps } from 'antd/es/typography/Text';
import type { TitleProps } from 'antd/es/typography/Title';

const Title = React.forwardRef<HTMLElement, TitleProps & React.RefAttributes<HTMLElement>>(
  (props, ref) => <OriginTypography.Title ref={ref} {...props} />,
);

const Paragraph = React.forwardRef<HTMLElement, ParagraphProps & React.RefAttributes<HTMLElement>>(
  (props, ref) => <OriginTypography.Paragraph ref={ref} {...props} />,
);

const Link = React.forwardRef<HTMLElement, LinkProps & React.RefAttributes<HTMLElement>>(
  (props, ref) => <OriginTypography.Link ref={ref} {...props} />,
);

const Text = React.forwardRef<HTMLElement, TextProps & React.RefAttributes<HTMLElement>>(
  (props, ref) => <OriginTypography.Text ref={ref} {...props} />,
);

export { Title, Link, Text, Paragraph };
  • 페이지 소스 맨 앞에 use client 태그를 추가해 페이지를 완전히 클라이언트 렌더링으로 만들 수도 있어요.
'use client';

// This is not real world code, just for explain
export default () => {
  return (
    <div className="App">
      <Form>
        <Form.Item>
          <Button type="primary">Button</Button>
        </Form.Item>
      </Form>
    </div>
  );
};

더 알아보기 (Learn more)