组件
排版 Typography
为标题、引言、正文、列表、引用和代码提供严格且优美的一致性阅读层级系统。
基础用法
使用 Typography 为产品页面提供规范且具备优雅阅读节奏的标题与正文层级:
Loading…
安装与引入
通过 CLI 自动添加组件,或手动复制源码至项目中:
pnpm dlx @wui-design/cli@latest add @wui/typography安装 Radix 原语与样式辅助依赖
pnpm add radix-ui class-variance-authority clsx tailwind-merge复制组件源码到
components/ui/typography.tsximport * as React from "react"
import { Slot } from "radix-ui"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const typographyVariants = cva("text-foreground", {
variants: {
variant: {
h1: "scroll-m-20 text-4xl font-semibold tracking-[-0.03em] text-balance lg:text-5xl",
h2: "scroll-m-20 text-3xl font-semibold tracking-[-0.025em] text-balance",
h3: "scroll-m-20 text-2xl font-semibold tracking-[-0.02em] text-balance",
h4: "scroll-m-20 text-xl font-semibold tracking-[-0.015em] text-balance",
body: "text-base leading-7 text-pretty",
lead: "text-muted-foreground text-xl leading-8 text-pretty",
small: "text-sm font-medium leading-5",
muted: "text-muted-foreground text-sm leading-6",
code: "bg-muted rounded-sm px-1.5 py-0.5 font-mono text-[0.875em] font-medium",
blockquote:
"border-border text-muted-foreground border-l-2 pl-4 text-base leading-7",
},
},
defaultVariants: { variant: "body" },
})
type TypographyVariant = NonNullable<
VariantProps<typeof typographyVariants>["variant"]
>
const defaultElements: Record<TypographyVariant, React.ElementType> = {
h1: "h1",
h2: "h2",
h3: "h3",
h4: "h4",
body: "p",
lead: "p",
small: "small",
muted: "p",
code: "code",
blockquote: "blockquote",
}
export interface TypographyProps
extends
React.HTMLAttributes<HTMLElement>,
VariantProps<typeof typographyVariants> {
/** 覆盖当前排版变体默认使用的 HTML 元素。 */
as?: React.ElementType
/** 将排版样式合并到唯一子元素。@default false */
asChild?: boolean
}
/** 为标题、正文和辅助文本提供一致的语义层级与阅读节奏。 */
function Typography({
className,
variant = "body",
as,
asChild = false,
...props
}: TypographyProps) {
const resolvedVariant = variant ?? "body"
const Comp = asChild ? Slot.Root : (as ?? defaultElements[resolvedVariant])
return (
<Comp
data-slot="typography"
data-variant={resolvedVariant}
className={cn(
typographyVariants({ variant: resolvedVariant }),
className
)}
{...props}
/>
)
}
/** 使用正文节奏排布有序或无序列表。 */
function TypographyList({
className,
ordered = false,
...props
}: React.HTMLAttributes<HTMLOListElement | HTMLUListElement> & {
/** 是否渲染为有序列表。@default false */
ordered?: boolean
}) {
const Comp = ordered ? "ol" : "ul"
return (
<Comp
data-slot="typography-list"
className={cn(
"marker:text-muted-foreground my-4 ml-6 space-y-2 text-base leading-7",
ordered ? "list-decimal" : "list-disc",
className
)}
{...props}
/>
)
}
/** 与正文颜色和焦点样式一致的文本链接。 */
function TypographyLink({ className, ...props }: React.ComponentProps<"a">) {
return (
<a
data-slot="typography-link"
className={cn(
"decoration-primary/35 hover:decoration-primary focus-visible:ring-ring/30 text-primary rounded-sm font-medium underline decoration-1 underline-offset-4 outline-none transition-[color,text-decoration-color,text-underline-offset] duration-200 ease-out hover:underline-offset-[5px] focus-visible:ring-[3px] motion-reduce:transition-none",
className
)}
{...props}
/>
)
}
export { Typography, TypographyLink, TypographyList, typographyVariants }
属性 Props
Typography Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| variant | "h1" | "h2" | "h3" | "h4" | "body" | "lead" | "small" | "muted" | "code" | "blockquote" | "body" | 排版文本的层级与视觉样式变体。自动关联默认底层 HTML 标签(如 h1 映射 <h1>,code 映射 <code>,body 映射 <p>)。 |
| as | React.ElementType | — | 覆盖当前变体默认使用的底层 HTML 元素标签(例如希望拥有 h2 样式的 <span> 或 <h3> 标签)。 |
| asChild | boolean | false | 是否使用 Radix Slot 将排版样式合并至唯一的子元素上。 |
| className | string | — | 应用于排版元素的额外 CSS 类名。 |
TypographyList Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| ordered | boolean | false | 是否渲染为数字有序列表 <ol>,默认 false 为圆点无序列表 <ul>。 |
| className | string | — | 应用于列表容器的额外 CSS 类名。 |
TypographyLink Props
继承原生 HTML <a> 锚点链接的全部属性,默认应用语义化焦点指示与下划线偏移;悬停时下划线颜色加深并轻微下移,系统开启“减少动态效果”时不做过渡。
事件 Events
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| onClick | (event: React.MouseEvent<HTMLElement>) => void | — | 透传原生点击事件。 |
| onMouseEnter / onMouseLeave | (event: React.MouseEvent<HTMLElement>) => void | — | 透传原生鼠标悬停事件。 |
使用场景与设计规范
Typography 统一控制全站文本排版规格,避免在业务代码中随意书写杂乱的字号与行高 class:
- 标题与字距(Tracking)微调:大字号标题(h1/h2)内置负字距(tight tracking)与
text-balance,防止换行时出现单字掉行。 - 行高与可读性(Leading):正文使用舒适的
leading-7行高,辅以text-pretty算法,在长段落阅读时保持眼睛对焦稳定。 - 语义与视觉解耦:当页面 SEO 结构与 UI 设计规范产生冲突时(例如侧边栏需要一个语义
<h2>但视觉要求small尺寸),使用<Typography variant="small" as="h2">实现无缝解耦。
场景示例
完整排版元素集合 (列表、引用与行内代码)
展示无序列表、有序列表、块级引用与行内代码样式的组合使用:
Loading…
多态标签与语义解耦
通过 as 属性自由切换底层渲染元素,兼顾文档大纲语义与设计系统视觉规范;示例中页面标题语义为 <h1>、视觉为 h3,小节标签语义为 <h2>、视觉为 small,“相关文章”则通过 asChild 把正文样式合并到自定义容器:
Loading…
无障碍与交互 Accessibility
- 文本换行优化:标题使用 CSS
text-wrap: balance,长正文使用text-wrap: pretty,杜绝孤字换行(Widows/Orphans),提升排版可读性。 - 清晰对比度:正文、弱化文本(muted)与代码块背景颜色均符合 WCAG 2.1 AA 级对比度标准。
- 可访问链接:
TypographyLink提供明确的下划线和高亮焦点环,色盲用户亦能清晰辨识可点击区域。