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 | - | × | |
카드 주변 테두리 렌더링 토글, variant를 사용하세요 |
boolean | true | × | ||
카드 본문 스타일, 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 | × | |
카드 헤드 스타일, 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)
- Tabs 컴포넌트 — 카드 탭
- Tag 컴포넌트 — 카드 내 태그
- Ant Design 시작하기 — 프로젝트 설정