Demos
How to import
import { Card } from '@fibrous/semi-ui-react';
Basic card
The basic card contains the title, content and other parts.
Code
import { Card, Typography } from '@fibrous/semi-ui-react';
export default function CardDemo() {
const { Text } = Typography;
return (
<Card title="Semi Design" style={{ maxWidth: 360 }} headerExtraContent={<Text link>更多</Text>}>
Semi Design 是由抖音前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。
</Card>
);
}Simple card
The card can only set the content area.
Code
import { IconInfoCircle } from '@fibrous/semi-icons-react';
import { Card, Popover, Avatar } from '@fibrous/semi-ui-react';
export default function CardDemo() {
const { Meta } = Card;
return (
<>
<Card style={{ maxWidth: 360 }}>Semi Design 是由抖音前端团队与 UED 团队共同设计开发并维护的设计系统。</Card>
<br />
<Card
style={{ maxWidth: 360 }}
bodyStyle={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<Meta title="Semi Doc" avatar={<Avatar alt="Card meta img" size="default" src="/assets/placeholder/logo.svg" />} />
<Popover position="top" showArrow content={<article style={{ padding: 6 }}>这是一个 Card</article>}>
<IconInfoCircle aria-label="信息" style={{ color: 'var(--semi-color-primary)' }} />
</Popover>
</Card>
</>
);
}Cover
You can use the cover property to set the cover.

Code
import { Card } from '@fibrous/semi-ui-react';
export default function CardDemo() {
const { Meta } = Card;
return (
<Card style={{ maxWidth: 300 }} cover={<img alt="example" src="/assets/root-web-sites/card-cover-docs-demo2.jpeg" />}>
<Meta title="卡片封面" />
</Card>
);
}Border and line
You can use bordered to set whether the card has an outer border, the default is true. At the same time, you can also use headerLine to set whether the content area and title area have borders, and footerLine to set whether the content area and footer area have borders.
Code
import { Card } from '@fibrous/semi-ui-react';
export default function CardDemo() {
return (
<div
style={{
display: 'inline-block',
padding: 20,
backgroundColor: 'var(--semi-color-fill-0)',
}}
>
<Card style={{ maxWidth: 360 }} bordered={false} headerLine title="Semi Design">
Semi Design 是由抖音前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。
</Card>
</div>
);
}Shadows
You can use shadows to set the timing of the shadow display. Optional: hover (show shadow when hover), always (show shadow always), if this property is not set, there will be no shadow.
Code
import { IconInfoCircle } from '@fibrous/semi-icons-react';
import { Card, Avatar, Popover } from '@fibrous/semi-ui-react';
export default function CardDemo() {
const { Meta } = Card;
return (
<div>
<Card
shadows="hover"
style={{ maxWidth: 360 }}
bodyStyle={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<Meta title="Semi Doc" avatar={<Avatar alt="Card meta img" size="default" src="/assets/placeholder/logo.svg" />} />
<Popover position="top" showArrow content={<article style={{ padding: 6 }}>这是一个 Card</article>}>
<IconInfoCircle aria-label="信息" style={{ color: 'var(--semi-color-primary)' }} />
</Popover>
</Card>
<br />
<Card
shadows="always"
style={{ maxWidth: 360 }}
bodyStyle={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<Meta title="Semi Doc" avatar={<Avatar alt="Card meta img" size="default" src="/assets/placeholder/logo.svg" />} />
<Popover position="top" showArrow content={<article style={{ padding: 6 }}>这是一个 Card</article>}>
<IconInfoCircle aria-label="信息" style={{ color: 'var(--semi-color-primary)' }} />
</Popover>
</Card>
</div>
);
}Customized content
You can use Card.Meta to support more flexible content, allowing you to set title, avatar, and description.
Code
import { Card, Avatar, Space, Button, Typography } from '@fibrous/semi-ui-react';
export default function CardDemo() {
const { Meta } = Card;
const { Text } = Typography;
return (
<Card
style={{ maxWidth: 340 }}
title={<Meta title="Semi Doc" description="全面、易用、优质" avatar={<Avatar alt="Card meta img" size="default" src="/assets/placeholder/logo.svg" />} />}
headerExtraContent={<Text link>More</Text>}
cover={<img alt="example" src="/assets/root-web-sites/card-cover-docs-demo.jpeg" />}
footerLine
footerStyle={{ display: 'flex', justifyContent: 'flex-end' }}
footer={
<Space>
<Button theme="borderless" type="primary">
精选案例
</Button>
<Button theme="solid" type="primary">
开始使用
</Button>
</Space>
}
>
Semi Design 是由抖音前端团队与 UED 团队共同设计开发并维护的设计系统。
</Card>
);
}Inner card
Other cards can be nested inside the card.
Code
import { Card, Typography } from '@fibrous/semi-ui-react';
export default function CardDemo() {
const { Text } = Typography;
return (
<Card title="Card title">
<Card title="Inner Card title" style={{ marginBottom: 20 }} headerExtraContent={<Text link>More</Text>}>
Inner Card content
</Card>
<Card title="Inner Card title" headerExtraContent={<Text link>More</Text>}>
Inner Card content
</Card>
</Card>
);
}Card in column
The system overview page is often combined with the grid.
Code
import { Card, Row, Col } from '@fibrous/semi-ui-react';
export default function CardDemo() {
return (
<div
style={{
backgroundColor: 'var(--semi-color-fill-0)',
padding: 20,
}}
>
<Row gutter={[16, 16]}>
<Col span={8}>
<Card title="Card Title" bordered={false}>
Card Content
</Card>
</Col>
<Col span={8}>
<Card title="Card Title" bordered={false}>
Card Content
</Card>
</Col>
<Col span={8}>
<Card title="Card Title" bordered={false}>
Card Content
</Card>
</Col>
</Row>
<Row gutter={[16, 16]}>
<Col span={16}>
<Card title="Card Title" bordered={false}>
Card Content
</Card>
</Col>
<Col span={8}>
<Card title="Card Title" bordered={false}>
Card Content
</Card>
</Col>
</Row>
</div>
);
}loading
You can use the loading property of Card to set whether to display placeholder elements in the card content area. When it is true, the placeholder elements will be displayed, and vice versa.
Code
import { useState } from 'react';
import { Card, Switch } from '@fibrous/semi-ui-react';
export default function CardDemo() {
const [loading, setLoading] = useState(true);
const { Meta } = Card;
return (
<>
<Switch aria-label="显示内容" onChange={(v) => setLoading(!v)} />
<br />
<br />
<Card style={{ maxWidth: 360 }} loading={loading}>
<Meta title="Semi Doc" description="全面、易用、优质" />
</Card>
</>
);
}With Skeleton
The loading property of Card can only set the preloading effect of the content area. If you want to set the preloading of other parts, or customize a richer preloading effect, you can combine it with the Skeleton component.
Code
import { useState } from 'react';
import { Card, Switch, Skeleton, Avatar, Typography } from '@fibrous/semi-ui-react';
export default function CardDemo() {
const [loading, setLoading] = useState(true);
const { Meta } = Card;
const { Title, Paragraph, Image } = Skeleton;
return (
<>
<Switch aria-label="显示内容" onChange={(v) => setLoading(!v)} />
<br />
<br />
<Card
style={{ maxWidth: 300 }}
title={
<Meta
title={
<Skeleton style={{ width: 80 }} placeholder={<Title />} loading={loading}>
<Typography.Title heading={5}>Semi Doc</Typography.Title>
</Skeleton>
}
description={
<Skeleton style={{ width: 150, marginTop: 12 }} placeholder={<Paragraph rows={1} />} loading={loading}>
<Typography.Text>全面、易用、优质</Typography.Text>
</Skeleton>
}
avatar={
<Skeleton placeholder={<Skeleton.Avatar />} loading={loading}>
<Avatar alt="Card meta img" size="default" src="/assets/placeholder/logo.svg" />
</Skeleton>
}
/>
}
headerExtraContent={
<Skeleton style={{ width: 50 }} placeholder={<Paragraph rows={1} />} loading={loading}>
<Typography.Text link>More</Typography.Text>
</Skeleton>
}
cover={
<Skeleton style={{ maxWidth: '100%', height: 220 }} placeholder={<Image />} loading={loading}>
<img alt="example" src="/assets/root-web-sites/card-cover-docs-demo.jpeg" />
</Skeleton>
}
/>
</>
);
}With tabs
You can use the Tabs component in the card component.
Code
import { Card, Tabs, TabPane } from '@fibrous/semi-ui-react';
export default function CardDemo() {
return (
<Card title="Card title">
<Tabs
type="line"
style={{
marginTop: -20,
marginBottom: -20,
}}
>
<TabPane tab="Tab 1" itemKey="1">
<p>content1</p>
<p>content1</p>
<p>content1</p>
</TabPane>
<TabPane tab="Tab 2" itemKey="2">
<p>content2</p>
<p>content2</p>
<p>content2</p>
</TabPane>
</Tabs>
</Card>
);
}Actions
actions receives the ReactNode array, and the elements will be displayed at the bottom of the content area with a horizontal spacing of 12px.

Code
import { Card, Rating } from '@fibrous/semi-ui-react';
export default function CardDemo() {
const { Meta } = Card;
return (
<Card style={{ maxWidth: 300 }} actions={[<Rating key="rating" size="small" defaultValue={4} />]} headerLine={false} cover={<img alt="example" src="/assets/root-web-sites/card-cover-docs-demo.jpeg" />}>
<Meta title="Semi Doc" description="全面、易用、优质" />
</Card>
);
}Card group
Use CardGroup to present the cards in an evenly spaced arrangement.
Code
import { useState } from 'react';
import { Card, CardGroup, Typography, Slider } from '@fibrous/semi-ui-react';
export default function CardDemo() {
const { Text } = Typography;
const [spacing, setSpacing] = useState(12);
return (
<>
<Text id="card-group-spacing">滑动调节 Card 间距</Text>
<Slider aria-labelledby="card-group-spacing" defaultValue={12} max={40} min={10} style={{ width: 360 }} onChange={(v) => typeof v === 'number' && setSpacing(v)} />
<br />
<CardGroup spacing={spacing}>
{Array.from({ length: 8 }).map((_v, idx) => (
<Card key={idx} shadows="hover" title="Card title" headerLine={false} style={{ width: 260 }} headerExtraContent={<Text link>More</Text>}>
<Text>Card content</Text>
</Card>
))}
</CardGroup>
</>
);
}Grid card
You can use the type property of CardGroup to set the card group to a grid type.
Code
import { Card, CardGroup, Typography } from '@fibrous/semi-ui-react';
export default function CardDemo() {
const { Text } = Typography;
return (
<CardGroup type="grid">
{Array.from({ length: 7 }).map((_v, idx) => (
<Card key={idx} shadows="hover" title="Card title" headerLine={false} style={{ width: 260 }} headerExtraContent={<Text link>More</Text>}>
<Text>Card content</Text>
</Card>
))}
</CardGroup>
);
}API reference
Card
Props
| Property | Description | Type | Default |
|---|---|---|---|
| actions | Actions at the bottom of the content area. Each array item is one action, spaced 12px apart horizontally. | ReactNode[] | - |
| aria-label | Accessible name of the card. The root element gets role="group" when it is set. | string | - |
| bodyStyle | Inline style of the content area. | CSSProperties | - |
| bordered | Whether the card has an outer border. | boolean | true |
| children | Content of the content area. A placeholder is shown while loading. | React.ReactNode | - |
| className | Class name of the root element. | string | - |
| cover | Card cover, below the header. | ReactNode | - |
| footer | Custom footer at the bottom of the card. | ReactNode | - |
| footerLine | Whether there is a border between the footer and the content area. | boolean | false |
| footerStyle | Inline style of the footer area. | CSSProperties | - |
| header | Custom header that replaces title and headerExtraContent. | ReactNode | - |
| headerExtraContent | Extra content to the right of the title. | ReactNode | - |
| headerLine | Whether there is a border between the header and the content area. | boolean | true |
| headerStyle | Inline style of the header area. | CSSProperties | - |
| loading | Whether the content area shows a loading placeholder. The root element's aria-busy is true while on. | boolean | false |
| ref | Reference to the root element (div). | TypeReact.Ref<HTMLDivElement> | - |
| shadows | When to show the shadow: hover or always. No shadow when unset. | Shadows | - |
| style | Inline style of the root element. | CSSProperties | - |
| title | Card title. A string renders as a div styled like a level-6 heading and truncated with a tooltip when too long. A ReactNode renders as is. | ReactNode | - |
id, onClick and other native attributes and events land on the root element (div).
CardGroup
Props
| Property | Description | Type | Default |
|---|---|---|---|
| align | Cross-axis alignment of the children, passed to Space: start, center, end or baseline. Defaults to center. | Align | - |
| children | Cards in the group. | React.ReactNode | - |
| className | Class name of the root element. | string | - |
| ref | Reference to the root element (div). | TypeReact.Ref<HTMLDivElement> | - |
| spacing | Spacing between cards, a number or [horizontal, vertical]. Ignored when type is grid. | number | [number, number] | 16 |
| style | Inline style of the root element. | React.CSSProperties | - |
| type | Set to grid for a grid layout, which overrides spacing. | CardGroupType | - |
| vertical | Whether to lay out vertically, passed to Space. Defaults to false. | boolean | - |
| wrap | Whether to wrap, passed to Space. Ignored when vertical. Defaults to true. | boolean | - |
id, onClick and other native attributes and events land on the root element of the inner Space.
Card.Meta
Props
| Property | Description | Type | Default |
|---|---|---|---|
| avatar | Avatar, to the left of the title and description. | React.ReactNode | - |
| className | Class name of the root element. | string | - |
| description | Description, below the title. | React.ReactNode | - |
| ref | Reference to the root element (div). | TypeReact.Ref<HTMLDivElement> | - |
| style | Inline style of the root element. | React.CSSProperties | - |
| title | Title content. | React.ReactNode | - |
id, onClick and other native attributes and events land on the root element (div).
Accessibility
- Card supports the input of
aria-labeloraria-labelledbyto indicate the function of the Card; the root element then getsrole="group"(an explicitrolewins) - When Card loading,
aria-busywill be turned on - A string
titleis styled as an h6 but rendered as adivwithout heading semantics, so it does not disturb the page's heading levels; pass your own heading element astitlewhen you need one (in Vue, put it in the#titleslot) - Card is a container-type component, and any elements inside the card need to follow their respective accessibility guidelines
Content Guidelines
- Card title
- Card titles should be informative and focus on the most important information
- try to limit the title to 1 phrase or segment
- Card titles should be written in sentence case
- do not end with punctuation marks (except question marks)
- Text
- Actionable: Use imperative sentences instead of "you can" to describe the body, which better tells the user what can be done
| ✅ Recommended usage | ❌ Deprecated usage |
|---|---|
| Get order progress for details | You can get order progress for details |
- Always say the most important information first
- Use "Need to" instead of "must"
Design Tokens
| Sass variable | Value | Usage |
|---|---|---|
| $color-card-bg-default | var(--semi-color-bg-0) | 卡片背景颜色 |
| $color-card-border | var(--semi-color-border) | 卡片描边颜色 |
| $color-card_title-text | var(--semi-color-text-0) | 卡片标题文字颜色 |
| $color-card_description-text | var(--semi-color-text-2) | 卡片描述文字颜色 |
| $color-card_extra-text | var(--semi-color-text-0) | 卡片附加文字颜色 |
| $color-card_body-text | var(--semi-color-text-1) | 卡片正文文字颜色 |
| $font-card_default-fontWeight | $font-weight-regular | 卡片文字字重 - 默认 |
| $font-card_extra-fontWeight | 700 | 卡片文字字重 - 附加文字 |
| $font-card_title-fontWeight | 700 | 卡片文字字重 - 标题 |
| $font-card_default-lineHeight | 20px | 卡片文字行高 - 默认 |
| $font-card_title-lineHeight | 22px | 卡片文字行高 - 标题 |
| $font-card_default-fontSize | $font-size-regular | 卡片文字大小 - 默认 |
| $font-card_extra-fontSize | $font-size-header-6 | 卡片文字大小 - 附加文字 |
| $font-card_title-fontSize | $font-size-header-6 | 卡片文字大小 - 标题 |
| $radius-card | var(--semi-border-radius-medium) | 卡片圆角 |
| $motion-card-transition_duration | 300ms | 卡片悬浮动画时长 |
| $width-card-border | $border-thickness-control | 卡片描边宽度 |
| $shadow-card | var(--semi-shadow-elevated) | 卡片阴影 |
| $spacing-card-padding | $spacing-base-loose | 卡片内边距 |
| $spacing-card-margin | $spacing-base-loose | 卡片外边距 |
| $spacing-card_avatar-marginRight | $spacing-base-tight | 卡片头像右侧外边距 |
| $spacing-cardGroup_card-margin | -1px | 卡片组外边距 |
| $z-card_hover | 1 | 悬浮后卡片 zindex |