REPO DEEP DIVE · 2026-07-29 · ANT-DESIGN/ANT-DESIGN · 기업용 React UI의 표준 교과서

ant-design/ant-design 딥다이브
"디자인 토큰 3단 변환"으로 배우는 대규모 CSS-in-JS 아키텍처

Ant Design(줄여서 antd)은 알리바바 계열 Ant Group이 만든 엔터프라이즈급 React UI 컴포넌트 라이브러리다. 버튼 하나부터 대형 데이터 테이블·폼·날짜 선택기까지 약 80개의 완성형 컴포넌트를 제공하며, 전 세계에서 가장 널리 쓰이는 React 디자인 시스템 중 하나다.

이 문서가 파고드는 핵심은 "디자인 토큰이 seed → map → alias 3단계를 거쳐 실제 CSS로 바뀌는 과정"이다. antd는 색상 하나, 여백 하나를 @ant-design/cssinjs 기반 런타임 CSS-in-JS 엔진으로 계산해 뿌리는데, 이 파이프라인을 이해하면 "테마 하나로 라이트/다크/컴팩트 모드를 동시에 지원"하는 원리가 보인다.

(저장소 ant-design/ant-design · 제작 Ant Design 팀(Ant Group) · 라이선스 MIT · 버전 6.5.2(2026년 v6 정식 릴리스 이후) · React 19 지원(peer는 React ≥18) · CSS-in-JS 엔진 @ant-design/cssinjs · 빌드 father 4 · 컴포넌트 약 80개 · 로케일(언어) 파일 약 74개 · 최신 커밋 4924d63, 2026-07-29)
목차
  1. 프로젝트 한 줄 정체
  2. 왜 지금 앤트디자인인가
  3. 무엇을 해결하는 라이브러리인가
  4. 전체 구조 한눈에 보기
  5. 핵심 설계·동작 원리 — 디자인 토큰 3단 변환
  6. 기술 스택과 의존성 지도
  7. 설치와 요구사항
  8. 실제 사용 흐름 — 코드로 보는 하루
  9. 함정과 오해 바로잡기
  10. 대안 비교 — MUI·Chakra·Mantine·shadcn/ui
  11. 정리 — 누가 쓰면 좋은가

1프로젝트 한 줄 정체

"레고 블록처럼 조립하는 완성형 React UI 컴포넌트 세트" + "그 블록을 색칠하는 디자인 토큰 엔진"

Ant Design은 두 겹으로 이루어져 있다. 겉으로 보이는 것은 <Button>, <Table>, <DatePicker> 같은 즉시 쓸 수 있는 완성형 컴포넌트 약 80개다. 그 밑을 받치는 것은 디자인 토큰(Design Token) 시스템으로, 색상·간격·둥근 정도 같은 값 하나하나를 "토큰"으로 관리하고 @ant-design/cssinjs라는 런타임 CSS-in-JS 엔진으로 실제 스타일을 생성한다.

단순한 컴포넌트 모음이 아니라 "디자인 언어(Design Language) + 구현체"라는 게 antd의 원래 정체성이다. 실제로 리포지토리 이름의 기원도 "Ant Design"이라는 디자인 스펙 문서였고, 이 저장소는 그 스펙을 React로 구현한 reference implementation이다. 그래서 컴포넌트 API뿐 아니라 테마·다크모드·RTL(오른쪽에서 왼쪽 언어)·SSR·국제화까지 한 몸에 갖췄다.

한 줄 비유

"완성된 가구 세트"이자 "그 가구를 원하는 색으로 다시 칠하는 도료 공장"

antd를 쓴다는 것은 이미 조립된 가구(컴포넌트)를 받는 것과 같다. 버튼도, 테이블도, 폼도 이미 다 만들어져 있어 그대로 갖다 쓰면 된다.

그런데 이 가구들은 전부 "토큰 공장(theme 시스템)"에서 나오는 도료로 마감된다. 공장 설정(seed 토큰)을 하나 바꾸면 — 예를 들어 "브랜드 색을 파랑에서 초록으로" — 80개 가구 전체의 색이 자동으로 다시 칠해진다. 가구 하나하나를 손으로 다시 칠할 필요가 없다.

용어
디자인 토큰 (Design Token)
"주 색상은 #1677ff", "기본 여백은 8px" 처럼 디자인 결정을 이름 붙인 변수로 저장한 것. 색을 코드 곳곳에 직접 적는 대신 토큰 하나만 바꾸면 전체 디자인이 일괄로 바뀐다.
용어
CSS-in-JS
CSS 파일을 따로 두지 않고 자바스크립트 코드 안에서 스타일을 계산해 브라우저에 <style> 태그로 주입하는 방식. antd는 이 방식을 이용해 "지금 계산된 토큰 값"을 그대로 CSS로 바꿔 넣는다.

2왜 지금 앤트디자인인가

10년 넘게 살아남은 "레퍼런스급" 디자인 시스템 · v6 CSS 변수 시대 · AI 코딩 에이전트 친화 실험장

React UI 라이브러리는 매년 새로 뜨고 진다. 그런데 antd는 2015년부터 지금까지 계속 실서비스에 쓰이며 살아남았고, 2026년 현재도 활발히 메이저 버전을 올리는(v6) 몇 안 되는 "레퍼런스급" 라이브러리다. 지금 다시 주목할 이유를 셋으로 정리하면:

① v6 — "CSS 변수 시대"로 정식 전환

2026년 기준 최신 정식 버전인 v6는 기술적으로 큰 전환점이다. CSS 변수(Custom Properties) 사용이 기본값이 되었고, 그 대신 더 이상 IE(인터넷 익스플로러)를 지원하지 않는다. React 17 이하 지원도 끊겼다(React 18+ 필수). "레거시를 다 버리고 현대 브라우저 표준에 올라탄" 결단이 이 시점에 나왔다는 것 자체가 주목할 이유다.

② "토큰 하나로 라이트/다크/컴팩트를 동시에" — 테마 엔진의 정석

antd의 ConfigProvider 테마 시스템은 "토큰 몇 개만 바꾸면 전체가 다시 칠해진다"는 것을 실제로 대규모 프로덕션 스케일에서 증명한 사례다. 최근 디자인 시스템 업계 전반이 토큰 기반 테마화(Design Tokens, W3C 표준화 논의 포함)로 수렴하는 흐름에서, antd의 seed→map→alias 파이프라인은 실전 구현 참고서 역할을 한다.

③ AI 코딩 에이전트에 발 빠르게 대응

저장소에는 AGENTS.md·CLAUDE.md는 물론 .claude/skills, .cursor/skills, public/.well-known/agent-skills 같은 AI 코딩 에이전트용 규칙·스킬 디렉터리가 이미 마련돼 있다. 여기에 대화형 AI UI 구성요소를 제공하는 자매 프로젝트 @ant-design/x도 의존성에 포함돼 있어, "AI 에이전트가 직접 코드를 짜고 리뷰하는 시대"에 맞춰 문서·규범을 정비하는 실험을 관찰할 수 있다.

규모가 주는 신뢰
80개 컴포넌트 · 74개 로케일 · Jest→Vitest 전환 진행 중

소스 트리에는 컴포넌트 소스·테스트·데모 파일을 합쳐 수천 개의 TypeScript 파일이 있고, 컴포넌트마다 단위 테스트·데모·영어/중국어 문서가 세트로 딸려 있다. 심지어 테스트 러너를 Jest에서 Vitest로 옮기는 vitest.config.ts POC(개념 증명)까지 저장소에 함께 커밋돼 있어, "오래된 프로젝트가 어떻게 점진적으로 현대화되는지" 실물로 볼 수 있다.

3무엇을 해결하는 라이브러리인가

"매번 버튼·테이블·폼을 새로 디자인·구현하지 말라" + "팀 전체가 하나의 시각 언어를 쓰게 하라"

기업용(엔터프라이즈) 웹 서비스 — 관리자 페이지, 백오피스, 대시보드, 내부 도구 — 를 만들 때 개발팀은 매번 같은 문제에 부딪힌다. "버튼 색은? 폼 검증 메시지는 어디에? 테이블 정렬 아이콘은?" 이런 자잘한 결정을 프로젝트마다 새로 내리면 시간이 새고, 제품마다 UI가 제각각이 된다.

antd는 이 문제를 "이미 검증된 완성형 컴포넌트 + 일관된 디자인 토큰"으로 해결한다. 개발자는 <Table columns={...} dataSource={...} /> 한 줄로 정렬·필터·페이지네이션이 되는 테이블을 얻고, 디자이너는 토큰 몇 개만 조정해 회사 브랜드에 맞는 색·둥근 정도를 전체 서비스에 일괄 적용한다. "매번 새로 그리기"에서 "토큰만 바꾸기"로 작업 단위를 바꿔준 것이 핵심 가치다.

여기에 국제화(74개 언어 로케일 파일), 접근성(RTL 레이아웃 지원), 서버사이드 렌더링(SSR) 스타일 추출까지 기본 제공되므로, 글로벌 서비스나 사내 다국어 백오피스를 만들 때 "이 부분은 antd가 이미 풀어놨다"고 믿고 넘어갈 수 있는 영역이 넓다.

비유

사무실 인테리어를 할 때 가구를 하나하나 목수에게 주문 제작하는 대신 이케아 카탈로그에서 골라 조립하는 것과 비슷하다. 다만 antd 카탈로그는 "회사 로고 색"만 입력하면 카탈로그 안의 모든 가구가 그 색에 맞춰 다시 인쇄되어 나온다는 점이 다르다.

4전체 구조 한눈에 보기

"컴포넌트(components/*) ← 디자인 토큰 엔진(theme/) ← CSS-in-JS 런타임(@ant-design/cssinjs)" 3계층

antd 저장소의 뼈대는 "각 컴포넌트가 자신의 스타일을 테마 엔진에게서 받아온다"는 구조다. 컴포넌트 자체(로직·마크업)와 스타일(토큰 기반 CSS-in-JS)이 물리적으로 분리돼 있고, 그 사이를 theme/ 디렉터리의 토큰 파이프라인이 연결한다.

┌────────────────────────────────────────────────────────────────┐ │ ANT DESIGN 전체 아키텍처 (단순화) │ └────────────────────────────────────────────────────────────────┘ [0] ConfigProvider (앱 최상단) theme={{ token, algorithm, components, cssVar }} · 앱 전체에 "지금 쓸 토큰 설정"을 React Context로 뿌린다 │ ▼ [1] theme/ — 디자인 토큰 파이프라인 (components/theme) seedToken (디자이너가 정하는 몇 개의 "씨앗" 값) │ derivative() — algorithm 함수 적용 ▼ MapToken (씨앗에서 파생된 팔레트 10단계 + 크기 체계) │ formatToken() — 개발자 편의용 별칭 부여 ▼ AliasToken (colorTextDisabled 처럼 "쓰임새 이름"이 붙은 최종 토큰) │ ▼ [2] 각 컴포넌트의 style/index.ts genStyleHooks('Button', token => [ ...CSSObject 스타일 ] ) · AliasToken + 컴포넌트별 ComponentToken 을 받아 스타일 객체 생성 │ ▼ [3] @ant-design/cssinjs (런타임 엔진) useStyleRegister — 스타일 객체를 해시로 캐싱하고 <style> 태그로 <head>에 주입 (한 번 계산되면 재사용) │ ▼ [4] 실제 DOM에 렌더링된 <button class="ant-btn ant-btn-css-var-abc123">

이 구조가 주는 이득은 명확하다. 토큰 계층(1)스타일 생성 계층(2)이 나뉘어 있어서, 새 테마를 추가할 때 컴포넌트 코드를 단 한 줄도 건드리지 않고 algorithm 함수만 바꿔 끼우면 된다. 실제로 antd는 defaultAlgorithm·darkAlgorithm·compactAlgorithm 세 가지를 기본 제공하며, 이들을 배열로 조합해 "다크 + 컴팩트"처럼 겹쳐 쓸 수도 있다.

5핵심 설계·동작 원리 — 디자인 토큰 3단 변환

seed → map(algorithm) → alias, 그리고 이를 실제 CSS로 굽는 genStyleHooks + cssVar 모드

이 섹션이 이 문서에서 가장 두꺼운 이유는, 이 3단 변환이 antd 전체를 관통하는 단 하나의 설계 원리이기 때문이다. 컴포넌트가 80개든 800개든, 이 파이프라인만 이해하면 "어디를 고치면 무엇이 바뀌는지" 예측할 수 있다. 실제 소스(components/theme/)를 따라가며 단계별로 뜯어본다.

① Seed Token — "디자이너가 정하는 씨앗 값"

가장 위층은 components/theme/themes/seed.ts에 정의된 SeedToken이다. colorPrimary(주 색상), fontSize(기본 글자 크기), borderRadius(둥근 정도), colorError 같은 30여 개의 "원시 값"만 담고 있다. 이것이 테마 커스터마이징의 유일한 입구다 — 나머지는 전부 이 씨앗에서 계산돼 나온다.

// components/theme/themes/seed.ts (요지)
export const defaultPresetColors: PresetColorType = {
  blue: '#1677ff', purple: '#722ed1', cyan: '#13c2c2',
  green: '#52c41a', magenta: '#eb2f96', red: '#f5222d', /* ... */
};
const seedToken: SeedToken = {
  ...defaultPresetColors,
  colorPrimary: '#1677ff',
  colorError: '#ff4d4f',
  fontSize: 14,
  borderRadius: 6,
  // ...
};

② Map Token — algorithm 함수가 씨앗을 팔레트로 "파생"시킨다

두 번째 층은 derivative(seedToken) 함수, 즉 algorithm이다. components/theme/themes/default/index.ts를 보면 colorPrimary 하나에서 @ant-design/colorsgenerate()를 이용해 10단계 색상 팔레트(blue-1 ~ blue-10)를 만들고, 글꼴 크기·여백·컨트롤 높이 체계까지 함께 계산한다. 결과가 MapToken이다.

// components/theme/themes/default/index.ts (요지)
export default function derivative(token: SeedToken): MapToken {
  const colorPalettes = /* colorPrimary → blue-1..blue-10 등 팔레트 생성 */;
  return {
    ...token,
    ...colorPalettes,
    ...genColorMapToken(token, { generateColorPalettes, generateNeutralColorPalettes }),
    ...genFontMapToken(token.fontSize),   // fontSizeSM/LG/XL... 자동 생성
    ...genSizeMapToken(token),             // sizeXXS ~ sizeXXL 자동 생성
    ...genControlHeight(token),
    ...genCommonMapToken(token),
  };
}

antd는 이 algorithm 함수를 3종 기본 제공한다. defaultAlgorithm(밝은 테마), darkAlgorithm(어두운 팔레트로 파생), compactAlgorithm(같은 색은 유지하되 크기·여백만 줄인 파생). ConfigProvideralgorithm: [theme.darkAlgorithm, theme.compactAlgorithm]처럼 배열로 넘기면 두 변환이 순서대로 겹쳐 적용된다.

③ Alias Token — "개발자가 실제로 쓰는 이름"으로 재포장

마지막 층은 components/theme/util/alias.tsformatToken()이다. colorFillContent, colorTextDisabled, controlItemBgHover처럼 "이 값이 어디 쓰이는지" 이름에 드러나는 별칭을 MapToken 값에서 다시 계산해 붙인다. 예를 들어 colorTextDisabledcolorTextQuaternary를 그대로 가리키는 별칭이다 — 실제 색상 계산은 이미 끝났고, 이 층은 "의미 있는 이름표"만 다는 단계다.

// components/theme/util/alias.ts (요지 발췌)
const aliasToken: AliasToken = {
  ...mergedToken,
  colorTextDisabled: mergedToken.colorTextQuaternary,
  colorTextHeading: mergedToken.colorText,
  controlItemBgHover: mergedToken.colorFillTertiary,
  controlItemBgActive: mergedToken.colorPrimaryBg,
  lineWidthFocus: mergedToken.lineWidth * 3,
  // override(사용자가 ConfigProvider로 넘긴 커스텀 값)가 최종적으로 이 위에 덮어써진다
  ...overrideTokens,
};
용어
seed → map → alias
seed는 사람이 정하는 소수의 원시 값, map은 그 값에서 자동 파생된 팔레트·크기 체계, alias는 "쓰임새 이름"이 붙은 최종 토큰. 셋을 나눠두면 "적게 입력하고 많이 얻는" 테마 시스템이 가능해진다.

④ genStyleHooks — 토큰을 실제 CSS 객체로 굽는 마지막 공정

컴포넌트 각각의 style/index.ts는 위에서 완성된 AliasToken을 받아 genStyleHooks('Button', token => [...]) 형태로 스타일을 등록한다. genStyleHooks·genComponentStyleHook·genSubStyleComponent는 antd가 자체 구현한 것이 아니라 공식 유틸 패키지 @ant-design/cssinjs-utils에서 가져와, 컴포넌트별 프리픽스·CSP nonce·해시 처리를 표준화한다.

// components/button/style/index.ts (요지)
export default genStyleHooks(
  'Button',
  (token) => {
    const buttonToken = prepareToken(token);
    return [
      genSharedButtonStyle(buttonToken),
      genSizeBaseButtonStyle(buttonToken),
      genVariantStyle(buttonToken),
      genGroupStyle(buttonToken),
    ];
  },
);

이 함수가 반환한 CSS 객체는 내부적으로 @ant-design/cssinjsuseStyleRegister해시로 캐싱한다. 즉 같은 토큰 조합으로 같은 컴포넌트를 100번 렌더링해도 스타일 계산과 <style> 태그 삽입은 최초 1회만 일어난다 — "런타임 CSS-in-JS는 무조건 느리다"는 통념을 정면으로 반박하는 캐싱 전략이다.

⑤ ConfigProvider — 토큰 설정을 트리 전체에 주입

이 모든 것을 코드 한 곳에서 켜는 진입점이 <ConfigProvider theme={...}>다. 내부적으로 algorithmcreateTheme()으로 감싸고, 사용자가 넘긴 token·components(컴포넌트별 오버라이드)를 DesignTokenContext.Provider로 하위 트리 전체에 뿌린다. 중첩된 ConfigProvider는 부모 테마를 이어받아 부분만 덮어쓸 수 있다.

import { ConfigProvider, theme } from 'antd';

function App() {
  return (
    <ConfigProvider
      theme={{
        algorithm: theme.darkAlgorithm,     // 다크 모드
        token: { colorPrimary: '#00b96b' }, // 브랜드 색만 교체
        components: { Button: { borderRadius: 2 } }, // 버튼만 각지게
      }}
    >
      <YourApp />
    </ConfigProvider>
  );
}

⑥ v6의 두 가지 렌더링 모드 — CSS 변수 vs 완전 정적(zero-runtime)

v6부터 antd는 기본적으로 CSS 변수 모드(cssVar)를 켠다. 스타일 규칙 자체는 미리 계산해 캐싱하되, 실제 색상 값은 var(--ant-color-primary) 같은 CSS 변수로 참조한다. 그래서 테마를 바꿀 때 전체 스타일시트를 다시 만드는 게 아니라 CSS 변수 값만 갱신하면 되어 훨씬 가볍다.

여기서 한 걸음 더 나아간 것이 zeroRuntime: true 옵션이다(6.0.0 신설). 이걸 켜면 런타임에는 아예 스타일을 생성하지 않고, 미리 빌드된 antd/dist/antd.css를 수동으로 불러와 쓰는 "완전 정적" 모드가 된다. 컴포넌트가 많은 대형 페이지에서 CSS-in-JS의 초기 계산 비용 자체를 없애고 싶을 때 쓰는 탈출구다.

함정
"CSS-in-JS라서 무조건 느리다"는 절반만 맞는 말

antd의 CSS-in-JS는 해시 기반 캐싱이 핵심이라, 같은 토큰 조합에서는 스타일 계산이 반복되지 않는다. 진짜 성능 이슈는 "테마(토큰)를 렌더링 중에 자주 바꾸는 코드"에서 생긴다 — 예를 들어 리스트 아이템마다 다른 ConfigProvider theme을 씌우면 캐시가 매번 새로 만들어진다. "정적인 테마 + 캐싱"이 기본 전제라는 점을 기억해야 한다.

⑦ SSR과 스타일 추출 — 서버에서 미리 계산해 넘기기

서버사이드 렌더링에서는 @ant-design/cssinjscreateCache() + <StyleProvider cache={cache}>로 렌더링 도중 생성된 스타일을 모아, extractStyle(cache)로 문자열을 뽑아 HTML <head>에 직접 삽입한다. 완전 정적 배포용으로는 @ant-design/static-style-extractextractStyle()런타임 없이 미리 CSS 파일을 뽑아내는 것도 가능하다 — 이게 위 ⑥의 zeroRuntime 모드와 짝을 이루는 도구다.

6기술 스택과 의존성 지도

React 19 · @ant-design/cssinjs · @rc-component/* 저수준 패키지군 · father 빌드 · biome+eslint 이중 린트

antd는 "자체 저수준 컴포넌트(headless) 패키지군 위에 완성형 컴포넌트를 얹는" 2층 생태계를 갖고 있다. 실제 package.jsondependencies 47개 중 절반 가까이가 @rc-component/* 스코프 패키지다.

영역실제 사용 패키지 / 버전
UI 프레임워크React 19.x(내부 개발) · peerDependencies는 react/react-dom >= 18.0.0(하위 호환)
CSS-in-JS 엔진@ant-design/cssinjs ^2.1.2 (런타임 스타일 등록·캐싱·SSR 추출) + @ant-design/cssinjs-utils ^2.1.2 (genStyleHooks 등 헬퍼)
색상 계산@ant-design/colors ^8, @ant-design/fast-color ^3 (팔레트 10단계 생성·색상 연산)
아이콘@ant-design/icons ^6 — v6과 버전이 강하게 결합(icons@6은 antd@5와 호환 안 됨)
저수준 헤드리스 컴포넌트@rc-component/table·select·picker·menu·dialog·trigger·tree30개 이상 — v6에서 옛 rc-* 네이밍을 @rc-component/* 스코프로 통합
날짜/시간dayjs ^1.11 (moment.js 대신 경량 날짜 라이브러리 채택)
빌드 도구father ~4.6 (umi 팀의 라이브러리 번들러) + 내부 antd-tools 스크립트 모음
린트/포맷eslint 10 + @antfu/eslint-configbiome 2.x 를 병행 도입 중(lint:script = eslint, lint:biome = biome)
테스트jest(기본, .jest.js) — 동시에 vitest 4 로 옮기는 POCvitest.config.ts에 커밋돼 있음(test:vitest 스크립트)
문서 사이트dumi(umi 기반 문서 프레임워크) · 각 컴포넌트는 index.en-US.md/index.zh-CN.md 쌍으로 문서화
용어
rc-* / @rc-component/*
antd의 각 컴포넌트를 실제로 구현하는 "스타일 없는(headless)" 저수준 React 패키지군. 예전에는 rc-table·rc-select처럼 접두어만 붙였는데, v6에서 @rc-component/table처럼 스코프 패키지로 정리됐다. antd는 이 위에 스타일·테마·한국어 등 로케일을 입힌 "완성본"이다.

버전의 진실원(source of truth)은 package.json뿐이다

antd는 자기 버전을 코드에서 components/version/version.ts로 export하는데, 이 파일은 저장소에 커밋돼 있지 않다(.gitignore에 등록). scripts/generate-version.ts가 빌드 시점에 package.jsonversion 필드를 읽어 이 파일을 그때그때 생성한다. 즉 "버전의 진짜 출처"는 항상 package.json 하나뿐이다.

7설치와 요구사항

React 18+ 필수 · 아이콘 패키지 버전 동기화 · 모던 브라우저 전제(IE 지원 종료)
# 설치 (npm / yarn / pnpm 모두 지원)
npm install antd
# 아이콘을 쓴다면 반드시 짝이 맞는 메이저 버전으로 함께 설치
npm install @ant-design/icons@6
항목요구사항
React 버전18.0.0 이상 필수(v6부터 17 이하 지원 종료). React 19 사용 시 @ant-design/v5-patch-for-react-19 패치 패키지는 더 이상 필요 없음(제거 권장)
아이콘 패키지@ant-design/iconsantd와 같은 메이저 버전으로 맞춰야 함 — icons@6은 antd@5와 호환되지 않음
브라우저CSS 변수를 기본 사용하는 모던 브라우저 전제. IE는 더 이상 지원되지 않음. browserslist: ["defaults"]
번들러Vite·webpack·Next.js 등 대부분의 현대 번들러와 호환. CSS-in-JS라 별도 CSS 전처리 설정이 필수는 아님
스타일 계산 없이 쓰기ConfigProvider theme={{ zeroRuntime: true }} + import 'antd/dist/antd.css' 조합으로 런타임 스타일 계산을 완전히 끌 수 있음
서버사이드 렌더링@ant-design/cssinjscreateCache/StyleProvider/extractStyle로 서버에서 만들어진 스타일을 HTML에 미리 심을 수 있음
주의
v5에서 그대로 올라오면 콘솔 경고가 쏟아진다

v6은 대부분의 컴포넌트 API 자체는 호환되지만, borderedvariant, dropdownClassNameclassNames.popup.root 처럼 수십 개의 prop이 "지원되지만 콘솔에 경고를 내는" 상태로 폐지 예고돼 있다(v7에서 완전 제거 예정). 마이그레이션 전에 공식 Ant Design CLI로 코드베이스를 스캔해 사용 중인 폐지 예정 API를 먼저 확인하는 것이 권장된다.

8실제 사용 흐름 — 코드로 보는 하루

설치 → ConfigProvider로 테마 걸기 → 컴포넌트 조립 → 폼 검증 → 다크모드 토글
단계 1

앱 최상단에 테마를 건다

가장 먼저 하는 일은 브랜드 색과 기본 값을 ConfigProvider에 한 번 설정하는 것이다. 이 설정은 하위 트리 전체에 자동으로 상속된다.

import { ConfigProvider } from 'antd';
import koKR from 'antd/locale/ko_KR';

export default function Root() {
  return (
    <ConfigProvider
      locale={koKR}
      theme={{ token: { colorPrimary: '#1677ff', borderRadius: 8 } }}
    >
      <App />
    </ConfigProvider>
  );
}
단계 2

완성형 컴포넌트를 조립한다 — 폼 + 테이블

버튼·폼·테이블은 이미 정렬·검증·반응형이 내장돼 있다. 아래는 흔한 검색-테이블 화면 골격이다.

import { Button, Form, Input, Table } from 'antd';

function UserSearch() {
  const [form] = Form.useForm();
  const columns = [
    { title: '이름', dataIndex: 'name' },
    { title: '이메일', dataIndex: 'email' },
  ];
  return (
    <>
      <Form form={form} layout="inline" onFinish={(v) => search(v)}>
        <Form.Item name="keyword" rules={[{ required: true }]}>
          <Input placeholder="이름으로 검색" />
        </Form.Item>
        <Button type="primary" htmlType="submit">검색</Button>
      </Form>
      <Table columns={columns} dataSource={users} rowKey="id" />
    </>
  );
}
단계 3

다크 모드는 algorithm 하나만 스위치

다크 모드 토글 버튼을 누르면 상태값 하나로 algorithm을 바꿔치기하면 끝이다 — 컴포넌트 코드는 전혀 건드리지 않는다.

import { ConfigProvider, theme } from 'antd';

function ThemedApp() {
  const [isDark, setIsDark] = useState(false);
  return (
    <ConfigProvider
      theme={{ algorithm: isDark ? theme.darkAlgorithm : theme.defaultAlgorithm }}
    >
      <App />
    </ConfigProvider>
  );
}

이 한 줄의 스위치 뒤에서 seed → map → alias 파이프라인 전체가 다시 계산되고, @ant-design/cssinjs가 새 해시로 스타일을 다시 캐싱한다 — 5장에서 본 파이프라인이 바로 여기서 매번 작동하는 것이다.

9함정과 오해 바로잡기

번들 크기 · "무조건 느리다" 통념 · 문서-코드 불일치 · 중국어 우선 개발 문화
함정 ①
"antd 하나 설치하면 번들이 커진다"는 부분적으로만 사실

antd는 ES 모듈(es/) 빌드를 제공해 모던 번들러 + 트리쉐이킹 조합에서는 실제 쓰는 컴포넌트만 번들에 들어간다. 문제는 아이콘이다 — @ant-design/icons에서 아이콘을 통째로 import하면 수백 개 아이콘이 딸려 온다. 개별 아이콘만 골라 import하는 습관이 필요하다.

함정 ②
문서의 "150+ 언어" ≠ 실제 로케일 파일 수

내부 AGENTS.md 문서는 "국제화(150+ 언어)"라고 적혀 있지만, 실제로 components/locale/ 디렉터리를 세어 보면 실제 언어 파일은 약 74개다(테스트·인덱스 파일 제외). 이런 문서와 실제 코드 수치의 괴리는 큰 오픈소스 프로젝트에서 흔하니, 숫자를 인용해야 할 때는 항상 소스를 직접 세어보는 습관이 안전하다.

함정 ③
"v6은 아직 준비 중"이 아니라 이미 정식 출시됐다

v6이 "다음 메이저 버전 예고편" 수준이라고 생각하기 쉽지만, 이 문서 작성 시점 기준 package.json의 버전은 이미 6.5.2이고 master 브랜치 자체가 v6이다. v5 기반 예제·블로그 글을 그대로 따라 하면 bordered, dropdownClassName 같은 폐지 예고 API 경고를 곧바로 만나게 된다.

함정 ④
중국어 우선 개발 문화 — 이슈·커밋의 실제 소통 언어

공식 문서와 API는 영/중 병기지만, 실제 이슈·PR 논의·내부 커밋 메시지에는 중국어가 섞여 있는 경우가 많다(팀 소속이 Ant Group이기 때문). 깊은 논쟁적 이슈나 설계 배경을 온전히 이해하려면 번역기를 함께 쓸 각오가 필요하다.

오해 바로잡기
"antd는 커스터마이징이 어렵다"는 옛말

v4~v5 초기까지는 Less 변수 오버라이드 방식이라 커스터마이징이 번거로웠지만, CSS-in-JS 기반 토큰 시스템으로 넘어온 뒤로는 ConfigProvidertoken/components 옵션만으로 컴포넌트별·트리별 세밀한 오버라이드가 표준 방법이 됐다. "antd는 다 파랗고 각져서 못 쓴다"는 인상은 대부분 v4 이전 경험에서 온 오해다.

10대안 비교 — MUI·Chakra·Mantine·shadcn/ui

"완성형 컴포넌트"라는 antd의 좌표를 다른 라이브러리들과 비교
라이브러리antd와 비교했을 때
MUI(Material UI)구글 Material 디자인을 따르는 가장 큰 경쟁자. 컴포넌트 수·생태계 규모는 비슷하나, MUI는 sx prop과 Emotion 기반, antd는 토큰 3단 변환 + ConfigProvider 기반이라 커스터마이징 진입점이 다르다. antd는 "엔터프라이즈 백오피스", MUI는 "범용 웹앱"에 더 자주 선택된다.
Chakra UI더 작고 유연한 스타일 프롭 중심 라이브러리. 완성도 높은 대형 컴포넌트(복잡한 Table·Form)는 antd가 훨씬 많고 무겁게 갖춰져 있는 반면, Chakra는 가볍게 처음부터 직접 조립하는 데 강하다.
Mantine비교적 최근 부상한 올인원 라이브러리로 훅(hooks) 생태계가 풍부하다. 컴포넌트 개수·완성도는 antd에 근접하지만, 엔터프라이즈 데이터 테이블·폼 검증의 성숙도는 antd가 오랜 실전 경험만큼 앞서는 편이다.
shadcn/ui완전히 다른 철학 — 라이브러리가 아니라 "복사해서 내 코드로 만드는" 컴포넌트 템플릿이다(Radix + Tailwind 기반). antd처럼 "설치 후 즉시 완성형" 접근과 정반대로, "내 코드베이스 안에서 자유롭게 뜯어고치고 싶다"는 팀에 맞는다.
비유

antd·MUI·Mantine은 "완제품 가구 브랜드"이고, Chakra는 "조립 부품이 많은 반제품 브랜드", shadcn/ui는 "설계도만 주고 내 집 목수가 직접 짜게 하는 것"에 가깝다. 어느 쪽이 낫냐가 아니라, 팀이 "빠르게 완성"과 "끝까지 커스터마이징" 중 무엇을 더 중요하게 여기는지에 달려 있다.

11정리 — 누가 쓰면 좋은가

엔터프라이즈 백오피스·대시보드 팀에게 가장 큰 이득 · 토큰 시스템은 모든 프론트엔드 개발자에게 좋은 공부거리

Ant Design은 "빠르게, 일관되게, 많은 기능을 갖춘 화면을 만들어야 하는" 팀에게 가장 어울린다. 특히 관리자 페이지·내부 도구·데이터 중심 대시보드처럼 디자인에 쓸 시간보다 기능 구현에 쓸 시간이 훨씬 중요한 프로젝트에서 강점이 극대화된다. 반대로 브랜드 아이덴티티가 강한 소비자용 서비스, 완전히 독자적인 시각 언어가 필요한 프로덕트에는 커스터마이징 부담이 상대적으로 크게 느껴질 수 있다.

그리고 antd를 쓰지 않더라도, 5장에서 다룬 seed→map→alias 토큰 파이프라인과 genStyleHooks 캐싱 전략은 어떤 규모의 디자인 시스템을 만들든 참고할 가치가 있는 설계다. "토큰 몇 개로 전체 테마를 바꾸는 시스템을 어떻게 짜는가"라는 질문에 실제 프로덕션 코드로 답을 볼 수 있는 몇 안 되는 저장소다.

이런 팀에 특히 잘 맞는다
사내 어드민 · 데이터 대시보드 · 다국어 B2B SaaS

테이블·폼·차트성 UI가 반복적으로 필요하고, 브랜드 색만 바꿔 여러 제품 라인에 재사용해야 하는 팀. 74개 로케일과 RTL 지원 덕분에 다국어·다지역 서비스에서 특히 시간을 아낄 수 있다.