代码演示
如何引入
import { Card } from '@fibrous/semi-ui-react';
基础卡片
基础卡片包含标题、内容等部分。
代码
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>
);
}简洁卡片
卡片可以只设置内容区域。
代码
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 属性设置封面。

代码
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>
);
}边线和外边框
可以使用 bordered 设置卡片是否有外边框,默认为 true 。同时,也可以使用 headerLine 设置内容区和标题区是否有边线, footerLine 设置内容区和页尾区是否有边线。
代码
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 设置显示阴影的时机,可选值为: hover(hover 时显示阴影)、always(始终显示阴影),如果不设置该属性则没有阴影。
代码
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>
);
}更灵活的内容展示
可以利用 Card.Meta 支持更灵活的内容,允许设置 title、avatar、description。
代码
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>
);
}内部卡片
卡片内部可以嵌套其他卡片。
代码
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>
);
}栅格卡片
在系统概览页面常常和栅格进行配合。
代码
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>
);
}内置预加载
可以使用 Card 的 loading 属性来设置卡片内容区是否显示占位元素,当它为 true 时将显示占位元素,反之则不显示。
代码
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>
</>
);
}更丰富的预加载效果
Card 自带的 loading 属性只能设置内容区的预加载效果,如果你想要设置其他部分的预加载,或者自定义更丰富的预加载效果,你可以结合 Skeleton 组件来实现。
代码
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>
}
/>
</>
);
}带页签的卡片
可以结合 Tabs 组件,实现带页签的卡片。
代码
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 接收 ReactNode 数组,元素间将以 12px 的水平间距展示于内容区底部。

代码
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>
);
}卡片组
CardGroup 中的卡片将呈现为等间距排列,利用 spacing 属性可以设置卡片间距大小。
代码
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>
</>
);
}网格型卡片组
使用 CardGroup 的 type 属性,可以将卡片组设置为网格型。
代码
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 参考
Card
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| actions | 卡片操作区,数组中的每个元素是一个操作,位于内容区底部,操作之间以 12px 的水平间距排列。 | ReactNode[] | - |
| aria-label | 卡片的可访问名称,传入后根元素的 role 为 group。 | string | - |
| bodyStyle | 卡片内容区的内联样式。 | CSSProperties | - |
| bordered | 是否显示卡片的外边框。 | boolean | true |
| children | 卡片内容区的内容,加载中时显示占位。 | React.ReactNode | - |
| className | 根元素的类名。 | string | - |
| cover | 卡片封面,位于标题区之下。 | ReactNode | - |
| footer | 自定义页脚,位于卡片底部。 | ReactNode | - |
| footerLine | 页脚区与内容区之间是否有边线。 | boolean | false |
| footerStyle | 页脚区的内联样式。 | CSSProperties | - |
| header | 自定义整个标题区,传入后取代 title 与 headerExtraContent。 | ReactNode | - |
| headerExtraContent | 标题右侧的额外内容。 | ReactNode | - |
| headerLine | 标题区与内容区之间是否有边线。 | boolean | true |
| headerStyle | 标题区的内联样式。 | CSSProperties | - |
| loading | 是否在内容区显示加载占位,开启时根元素的 aria-busy 为 true。 | boolean | false |
| ref | 根元素(div)的引用。 | TypeReact.Ref<HTMLDivElement> | - |
| shadows | 显示阴影的时机,可选 hover 或 always;不设置则没有阴影。 | Shadows | - |
| style | 根元素的内联样式。 | CSSProperties | - |
| title | 卡片标题。字符串按 6 级标题的样式渲染为 div,超长时省略并显示提示;传入 ReactNode 时原样渲染。 | ReactNode | - |
id、onClick 等原生属性与事件落在卡片的根元素(div)上。
CardGroup
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| align | 子项的交叉轴对齐方式,透传给 Space,可选 start、center、end 或 baseline,默认 center。 | Align | - |
| children | 组内的卡片。 | React.ReactNode | - |
| className | 根元素的类名。 | string | - |
| ref | 根元素(div)的引用。 | TypeReact.Ref<HTMLDivElement> | - |
| spacing | 卡片间距,数值或 [水平间距, 垂直间距];type 为 grid 时不生效。 | number | [number, number] | 16 |
| style | 根元素的内联样式。 | React.CSSProperties | - |
| type | 设为 grid 时呈现为网格型,覆盖 spacing。 | CardGroupType | - |
| vertical | 是否纵向排列,透传给 Space,默认 false。 | boolean | - |
| wrap | 是否换行,透传给 Space;纵向排列时不生效,默认 true。 | boolean | - |
id、onClick 等其他原生属性与事件落在内部 Space 的根元素上。
Card.Meta
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| avatar | 头像,位于标题与描述的左侧。 | React.ReactNode | - |
| className | 根元素的类名。 | string | - |
| description | 描述内容,位于标题之下。 | React.ReactNode | - |
| ref | 根元素(div)的引用。 | TypeReact.Ref<HTMLDivElement> | - |
| style | 根元素的内联样式。 | React.CSSProperties | - |
| title | 标题内容。 | React.ReactNode | - |
id、onClick 等原生属性与事件落在根元素(div)上。
Accessibility
- Card 支持传入
aria-label或aria-labelledby来表示该 Card 作用,传入后根元素带role="group"(传入的role优先) - Card loading 时,将开启
aria-busy - 字符串
title按 h6 的样式渲染,但元素是div,不带标题语义,不会打乱页面的标题层级;需要标题语义时,传入自己的标题元素作为title(Vue 中写在#title插槽里) - Card 为容器型组件,卡片内部的任何元素需要遵循各自的可访问性指南
文案规范
- 卡片标题
- 卡片标题应具有信息描述性,聚焦最重要的信息
- 尽量将标题限制在 1 个短语或句段中
- 卡片标题应句子大小写书写
- 不要以标点符号结尾(除了问号)
- 正文
- 可操作的:使用祈使句而不是“你可以”来描述正文,可以更好的告诉用户可以做什么
| ✅ 推荐用法 | ❌ 不推荐用法 |
|---|---|
| Get order progress for details | You can get order progress for details |
- 总是优先说最重要的信息
- 使用 “Need to”而不是”must“
设计变量
| Sass 变量 | 值 | 用法 |
|---|---|---|
| $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 |