Card

Card (카드)

Card는 하나의 주제와 관련된 콘텐츠를 표시하는 데 사용하는 컴포넌트예요. 다양한 타입과 크기의 요소를 포함할 수 있어요.

출처: 문서

본문

언제 사용하나요

Card는 하나의 주제와 관련된 콘텐츠를 표시하는 데 사용할 수 있어요. 콘텐츠는 다양한 타입과 크기의 여러 요소로 구성될 수 있죠.

예제 (Examples)

기본 카드 (Basic card)

제목, 콘텐츠, 우측 상단 추가 콘텐츠를 포함하는 기본 카드예요. medium과 small 두 가지 크기를 지원해요.

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

const App: React.FC = () => (
  <Space vertical size={16}>
    <Card title="Default size card" extra={<a href="#">More</a>} style={{ width: 300 }}>
      <p>Card content</p>
      <p>Card content</p>
      <p>Card content</p>
    </Card>
    <Card size="small" title="Small size card" extra={<a href="#">More</a>} style={{ width: 300 }}>
      <p>Card content</p>
      <p>Card content</p>
      <p>Card content</p>
    </Card>
  </Space>
);

export default App;

테두리 없음 (No border)

회색 배경 위의 테두리 없는 카드예요.

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

const App: React.FC = () => (
  <Card title="Card title" variant="borderless" style={{ width: 300 }}>
    <p>Card content</p>
    <p>Card content</p>
    <p>Card content</p>
  </Card>
);

export default App;

단순 카드 (Simple card)

콘텐츠 영역만 포함하는 단순한 카드예요.

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

const App: React.FC = () => (
  <Card style={{ width: 300 }}>
    <p>Card content</p>
    <p>Card content</p>
    <p>Card content</p>
  </Card>
);

export default App;

커스터마이즈된 콘텐츠 (Customized content)

Card.Meta를 사용해 더 유연한 콘텐츠를 지원할 수 있어요.

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

const { Meta } = Card;

const App: React.FC = () => (
  <Card
    hoverable
    variant="borderless"
    style={{ width: 240 }}
    cover={
      <img
        draggable={false}
        alt="example"
        src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png"
      />
    }
  >
    <Meta title="Europe Street beat" description="www.instagram.com" />
  </Card>
);

export default App;

컬럼 카드 (Card in column)

카드는 보통 개요 페이지에서 그리드 컬럼 레이아웃과 협력해요.

import React from 'react';
import { Card, Col, Row } from 'antd';

const App: React.FC = () => (
  <Row gutter={16}>
    <Col span={8}>
      <Card title="Card title" variant="borderless">
        Card content
      </Card>
    </Col>
    <Col span={8}>
      <Card title="Card title" variant="borderless">
        Card content
      </Card>
    </Col>
    <Col span={8}>
      <Card title="Card title" variant="borderless">
        Card content
      </Card>
    </Col>
  </Row>
);

export default App;

로딩 카드 (Loading card)

카드 콘텐츠를 가져오는 동안 로딩 표시기를 보여줘요.

import React, { useState } from 'react';
import { EditOutlined, EllipsisOutlined, SettingOutlined } from '@ant-design/icons';
import { Avatar, Card, Flex, Switch } from 'antd';

const actions: React.ReactNode[] = [
  <EditOutlined key="edit" />,
  <SettingOutlined key="setting" />,
  <EllipsisOutlined key="ellipsis" />,
];

const App: React.FC = () => {
  const [loading, setLoading] = useState<boolean>(true);
  return (
    <Flex gap="medium" align="start" vertical>
      <Switch
        aria-label="Show card content"
        checked={!loading}
        onChange={(checked) => setLoading(!checked)}
      />
      <Card loading={loading} actions={actions} style={{ minWidth: 300 }}>
        <Card.Meta
          avatar={<Avatar src="https://api.dicebear.com/10.x/lorelei/svg?seed=1" />}
          title="Card title"
          description={
            <>
              <p>This is the description</p>
              <p>This is the description</p>
            </>
          }
        />
      </Card>
      <Card loading={loading} actions={actions} style={{ minWidth: 300 }}>
        <Card.Meta
          avatar={<Avatar src="https://api.dicebear.com/10.x/lorelei/svg?seed=2" />}
          title="Card title"
          description={
            <>
              <p>This is the description</p>
              <p>This is the description</p>
            </>
          }
        />
      </Card>
    </Flex>
  );
};

export default App;

그리드 카드 (Grid card)

그리드 스타일의 카드 콘텐츠예요.

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

const gridStyle: React.CSSProperties = {
  width: '25%',
  textAlign: 'center',
};

const App: React.FC = () => (
  <Card title="Card Title">
    <Card.Grid style={gridStyle}>Content</Card.Grid>
    <Card.Grid hoverable={false} style={gridStyle}>
      Content
    </Card.Grid>
    <Card.Grid style={gridStyle}>Content</Card.Grid>
    <Card.Grid style={gridStyle}>Content</Card.Grid>
    <Card.Grid style={gridStyle}>Content</Card.Grid>
    <Card.Grid style={gridStyle}>Content</Card.Grid>
    <Card.Grid style={gridStyle}>Content</Card.Grid>
  </Card>
);

export default App;

내부 카드 (Inner card)

일반 카드 안에 배치해 다단계 구조의 정보를 표시할 수 있어요.

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

const App: React.FC = () => (
  <Card title="Card title">
    <Card type="inner" title="Inner Card title" extra={<a href="#">More</a>}>
      Inner Card content
    </Card>
    <Card
      style={{ marginTop: 16 }}
      type="inner"
      title="Inner Card title"
      extra={<a href="#">More</a>}
    >
      Inner Card content
    </Card>
  </Card>
);

export default App;

탭과 함께 (With tabs)

더 많은 콘텐츠를 호스팅할 수 있어요.

import React, { useState } from 'react';
import { Card } from 'antd';

const tabList = [
  {
    key: 'tab1',
    tab: 'tab1',
  },
  {
    key: 'tab2',
    tab: 'tab2',
  },
];

const contentList: Record<string, React.ReactNode> = {
  tab1: <p>content1</p>,
  tab2: <p>content2</p>,
};

const tabListNoTitle = [
  {
    key: 'article',
    label: 'article',
  },
  {
    key: 'app',
    label: 'app',
  },
  {
    key: 'project',
    label: 'project',
  },
];

const contentListNoTitle: Record<string, React.ReactNode> = {
  article: <p>article content</p>,
  app: <p>app content</p>,
  project: <p>project content</p>,
};

const App: React.FC = () => {
  const [activeTabKey1, setActiveTabKey1] = useState<string>('tab1');
  const [activeTabKey2, setActiveTabKey2] = useState<string>('app');

  const onTab1Change = (key: string) => {
    setActiveTabKey1(key);
  };
  const onTab2Change = (key: string) => {
    setActiveTabKey2(key);
  };

  return (
    <>
      <Card
        style={{ width: '100%' }}
        title="Card title"
        extra={<a href="#">More</a>}
        tabList={tabList}
        activeTabKey={activeTabKey1}
        onTabChange={onTab1Change}
      >
        {contentList[activeTabKey1]}
      </Card>
      <br />
      <br />
      <Card
        style={{ width: '100%' }}
        tabList={tabListNoTitle}
        activeTabKey={activeTabKey2}
        tabBarExtraContent={<a href="#">More</a>}
        onTabChange={onTab2Change}
        tabProps={{ size: 'medium' }}
      >
        {contentListNoTitle[activeTabKey2]}
      </Card>
    </>
  );
};

export default App;

더 많은 콘텐츠 설정 지원 (Support more content configuration)

cover, avatar, title, description을 지원하는 카드예요.

import React from 'react';
import { EditOutlined, EllipsisOutlined, SettingOutlined } from '@ant-design/icons';
import { Avatar, Card } from 'antd';

const { Meta } = Card;

const App: React.FC = () => (
  <Card
    style={{ width: 300 }}
    cover={
      <img
        draggable={false}
        alt="example"
        src="https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png"
      />
    }
    actions={[
      <SettingOutlined key="setting" />,
      <EditOutlined key="edit" />,
      <EllipsisOutlined key="ellipsis" />,
    ]}
  >
    <Meta
      avatar={<Avatar src="https://api.dicebear.com/10.x/lorelei/svg?seed=8" />}
      title="Card title"
      description="This is the description"
    />
  </Card>
);

export default App;

커스텀 시맨틱 DOM 스타일링

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

import React from 'react';
import { EditOutlined, HeartOutlined, ShareAltOutlined } from '@ant-design/icons';
import { Avatar, Button, Card, Flex } from 'antd';
import type { CardMetaProps, CardProps, GetProp } from 'antd';
import { createStyles } from 'antd-style';

const { Meta } = Card;

const useStyles = createStyles(({ token }) => ({
  root: {
    width: 300,
    backgroundColor: token.colorBgContainer,
    borderRadius: token.borderRadius,
    boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
    border: `${token.lineWidth}px ${token.lineType} ${token.colorBorderSecondary}`,
  },
  header: {
    borderBottom: 'none',
    paddingBottom: token.paddingXS,
  },
  body: {
    paddingTop: 0,
  },
}));

const stylesCard: CardProps['styles'] = {
  root: {
    boxShadow: '0 2px 8px rgba(0,0,0,0.06)',
    borderRadius: 8,
  },
  title: {
    fontSize: 16,
    fontWeight: 500,
  },
};

const stylesCardFn: CardProps['styles'] = (info): GetProp<CardProps, 'styles', 'Return'> => {
  if (info.props.variant === 'outlined') {
    return {
      root: {
        borderColor: '#696FC7',
        boxShadow: '0 2px 8px #A7AAE1',
        borderRadius: 8,
      },
      extra: {
        color: '#696FC7',
      },
      title: {
        fontSize: 16,
        fontWeight: 500,
        color: '#A7AAE1',
      },
    };
  }
};

const stylesCardMeta: CardMetaProps['styles'] = {
  title: {
    color: '#A7AAE1',
  },
  description: {
    color: '#A7AAE1',
  },
};

const actions = [
  <HeartOutlined key="heart" style={{ color: '#ff6b6b' }} />,
  <ShareAltOutlined key="share" style={{ color: '#4ecdc4' }} />,
  <EditOutlined key="edit" style={{ color: '#45b7d1' }} />,
];

const App: React.FC = () => {
  const { styles: classNames } = useStyles();

  const sharedCardProps: CardProps = {
    classNames,
    actions,
  };

  const sharedCardMetaProps: CardMetaProps = {
    avatar: <Avatar src="https://api.dicebear.com/10.x/lorelei/svg?seed=1" />,
    description: 'This is the description',
  };

  return (
    <Flex gap="medium">
      <Card
        {...sharedCardProps}
        title="Object Card"
        styles={stylesCard}
        extra={<Button type="link">More</Button>}
        variant="borderless"
      >
        <Meta {...sharedCardMetaProps} title="Object Card Meta title" />
      </Card>
      <Card
        {...sharedCardProps}
        title="Function Card"
        styles={stylesCardFn}
        extra={
          <Button type="link" styles={{ root: { color: '#A7AAE1' } }}>
            More
          </Button>
        }
      >
        <Meta {...sharedCardMetaProps} styles={stylesCardMeta} title="Function Card Meta title" />
      </Card>
    </Flex>
  );
};

export default App;

API

공통 props 참고: Common props

<Card title="Card title">Card content</Card>
속성 설명 타입 기본값 버전 전역 설정
actions 액션 리스트, Card 하단에 표시 Array<ReactNode> - ×
activeTabKey 현재 TabPane의 key string - ×
bordered 카드 주변 테두리 렌더링 토글, variant를 사용하세요 boolean true ×
bodyStyle 카드 본문 스타일, styles.body를 사용하세요 CSSProperties - - ×
variant Card의 변형 outlined | borderless outlined 5.24.0 5.24.0
classNames 컴포넌트 내부 각 시맨틱 구조의 클래스 커스터마이즈. 객체 또는 함수 지원 Record<SemanticDOM, string> | (info: { props })=> Record<SemanticDOM, string> - 5.14.0
cover 카드 커버 ReactNode - ×
defaultActiveTabKey activeTabKey가 설정되지 않았을 때의 초기 활성 TabPane key string 첫 번째 탭의 key ×
extra 카드 우측 상단에 렌더링할 콘텐츠 ReactNode - ×
hoverable 카드에 호버할 때 띄우기 boolean false ×
headStyle 카드 헤드 스타일, styles.header를 사용하세요 CSSProperties - - ×
loading 카드 콘텐츠를 가져오는 동안 로딩 표시기 표시 boolean false ×
size 카드 크기 medium | small medium ×
tabBarExtraContent 탭 바의 추가 콘텐츠 ReactNode - ×
tabList TabPane 헤드 리스트 TabItemType[] - ×
tabProps Tabs - - ×
title 카드 제목 ReactNode - ×
type 카드 스타일 타입, inner로 설정하거나 설정하지 않음 string - ×
styles 컴포넌트 내부 각 시맨틱 구조의 인라인 스타일 커스터마이즈. 객체 또는 함수 지원 Record<SemanticDOM, CSSProperties> | (info: { props })=> Record<SemanticDOM, CSSProperties> - 5.14.0
onTabChange 탭 전환 시 콜백 (key) => void - ×

Card.Grid

속성 설명 타입 기본값 버전
hoverable 카드 그리드에 호버할 때 띄우기 boolean true

Card.Meta

속성 설명 타입 기본값 버전 전역 설정
avatar 아바타 또는 아이콘 ReactNode - ×
description 설명 콘텐츠 ReactNode - ×
title 제목 콘텐츠 ReactNode - ×

시맨틱 DOM (Semantic DOM)

Card

https://ant.design/components/card/semantic.md

Card.Meta

https://ant.design/components/card/semantic_meta.md

디자인 토큰 (Design Token)

컴포넌트 토큰 (Card)

토큰 이름 설명 타입 기본값
actionsBg 카드 액션의 배경색 string #ffffff
actionsLiMargin 카드 액션 각 항목의 여백 string 12px 0
bodyPadding 카드 본문의 패딩 number 24
bodyPaddingSM 작은 카드 본문의 패딩 number 12
extraColor extra 영역의 텍스트 색 string rgba(0,0,0,0.88)
headerBg 카드 헤더의 배경색 string transparent
headerFontSize 카드 헤더의 폰트 크기 string | number 16
headerFontSizeSM 작은 카드 헤더의 폰트 크기 string | number 14
headerHeight 카드 헤더의 높이 string | number 56
headerHeightSM 작은 카드 헤더의 높이 string | number 38
headerPadding 카드 헤드의 패딩 number 24
headerPaddingSM 작은 카드 헤드의 패딩 number 12
tabsMarginBottom tabs 컴포넌트의 하단 여백 number -17

전역 토큰 (Global Token)

토큰 이름 설명 타입 기본값
borderRadiusLG LG 크기 테두리 반지름, Card, Modal 등 큰 반지름 컴포넌트에 사용 number
boxShadowTertiary 요소의 3차 box shadow 스타일 제어. string
colorBgContainer 컨테이너 배경색. 예: 기본 버튼, 입력박스 등. colorBgElevated와 혼동하지 말 것. string
colorBorderSecondary 기본 테두리색보다 약간 밝은 색, colorSplit과 같음. 단색 사용. string
colorFillAlter 요소의 대체 배경색 제어. string
colorIcon 약한 액션. 예: allowClear 또는 Alert 닫기 버튼 string
colorPrimary 브랜드 색. 제품의 특성과 커뮤니케이션을 반영하는 가장 직접적인 시각 요소. 선택하면 완전한 색 팔레트가 자동 생성 string
colorText W3C 표준을 준수하는 기본 텍스트 색. 가장 어두운 중성색이기도 함. string
colorTextDescription 텍스트 설명의 폰트 색 제어. string
colorTextHeading 제목의 폰트 색 제어. string
fontFamily 시스템 기본 인터페이스 폰트와 화면 표시에 적합한 대체 폰트 라이브러리 세트 제공 string
fontSize 디자인 시스템에서 가장 널리 사용되는 폰트 크기. number
fontSizeLG 큰 폰트 크기 number
fontWeightStrong 제목 컴포넌트(h1, h2, h3 등)나 선택 항목의 폰트 두께 제어. number
lineHeight 텍스트의 줄 높이. number
lineType 기본 컴포넌트의 테두리 스타일 string
lineWidth 기본 컴포넌트의 테두리 너비 number
marginXS 요소의 여백 제어, 작은 크기. number
marginXXS 요소의 여백 제어, 가장 작은 크기. number
motionDurationMid 모션 속도, 중간 속도. 중간 요소 애니메이션 상호작용에 사용. string
padding 요소의 패딩 제어. number
paddingLG 요소의 큰 패딩 제어. number

더 알아보기 (Learn more)