wui
组件

排版 Typography

为标题、引言、正文、列表、引用和代码提供严格且优美的一致性阅读层级系统。

第三方依赖 · radix-ui第三方依赖 · class-variance-authority

基础用法

使用 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.tsx
components/ui/typography.tsx
import * 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>)。
asReact.ElementType—覆盖当前变体默认使用的底层 HTML 元素标签(例如希望拥有 h2 样式的 <span> 或 <h3> 标签)。
asChildbooleanfalse是否使用 Radix Slot 将排版样式合并至唯一的子元素上。
classNamestring—应用于排版元素的额外 CSS 类名。

TypographyList Props

属性类型默认值说明
orderedbooleanfalse是否渲染为数字有序列表 <ol>,默认 false 为圆点无序列表 <ul>。
classNamestring—应用于列表容器的额外 CSS 类名。

继承原生 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 提供明确的下划线和高亮焦点环,色盲用户亦能清晰辨识可点击区域。