shadcn-ui/cn · 上手攻略

  • 仓库:shadcn-ui/cn
  • 链接:https://github.com/shadcn-ui/cn
  • 分类:frontend · utility · tailwind
  • 作者:Tom
  • 更新:2026-09-04

这是什么

shadcn-ui/cn 是一个 Tailwind CSS 类名合并与冲突解决引擎,由 shadcn 和 aidenybai 联合开发。它的定位非常明确:同时替代 tailwind-mergetwMerge)和 clsx,提供相同的 API、完整的功能兼容,以及 30 倍以上的性能提升

核心特点: - 零依赖(zero dependencies) - 框架无关(React / Vue / Svelte / Solid / Astro / 纯 HTML 模板均可用) - 运行环境无关(浏览器 / Node / Bun / Deno / Edge) - 无需使用 shadcn/ui 本身,任何 Tailwind CSS 项目均可接入

2026 年 9 月 2 日正式开源,不到一周约 267 Stars(截至查询时),热度极高。


解决什么问题

在 Tailwind CSS 项目中,条件类名的处理一直是痛点:

// 你原本需要两个包:
import { clsx } from "clsx";       // 条件拼接
import { twMerge } from "tailwind-merge";  // 冲突解决

// 然后手写一个 cn() 封装
export function cn(...inputs) {
  return twMerge(clsx(inputs));
}

cn 把这个模式直接打包成一个函数,同时完成 clsx 的条件拼接和 tailwind-merge 的冲突解决,并且速度更快。


快速安装

# 方式一:一键迁移(推荐,已有的 shadcn/ui 项目)
npx shadcn@latest migrate cn

# 方式二:全新安装
npm i cn

# 或 Bun
bun add cn

# 或 pnpm
pnpm add cn

迁移已有项目

如果已有 lib/utils.ts 中的 cn 封装:

// lib/utils.ts —— 旧写法
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

// 新写法 —— 直接替换
export { cn } from "cn";

然后删除 clsxtailwind-merge 依赖:

npm uninstall clsx tailwind-merge

⚠️ 注意:如果其他包仍然导入 clsxtailwind-merge,可以用 alias 桥接,参见 aliasing 文档


核心用法

基本 API

import { cn } from "cn";

// 字符串拼接
cn("px-2 py-1", "bg-blue-500")
// → "px-2 py-1 bg-blue-500"

// 条件类名(clsx 语义)
cn("px-2", isActive && "bg-blue-500", { "text-white": isActive })
// → isActive=true 时:"px-2 bg-blue-500 text-white"
// → isActive=false 时:"px-2"

// 冲突解决(tailwind-merge 语义)
cn("p-4 p-2 p-6")
// → "p-6"  (取最后一个同组类名)

// 混用
cn(
  "rounded-md px-4 py-2 text-sm",
  isActive && "bg-primary",
  { "opacity-50": disabled }
)

进阶配置(与 tailwind-merge 完全兼容)

import { createCn } from "cn/config";

// 自定义扩展(与 extendTailwindMerge 相同用法)
const cn = createCn({
  extend: {
    classGroups: {
      "font-size": [{ text: ["hero"] }]
    }
  }
});

// Tailwind v4 前缀支持
const cn = createCn({ prefix: "tw" });
cn("tw-text-xl")  // → "tw-text-xl"

Tailwind-merge 兼容性对照

tailwind-merge cn 中的对应
twMerge(...) cn(...)(直接调用)
twJoin(...) cn(...)(相同语义)
extendTailwindMerge(ext) createCn(ext) from cn/config
createTailwindMerge(fn) createTwMerge(fn) from cn/config
getDefaultConfig() defaultConfig() from cn/config

编译时优化(cn/build)

如果对包体积敏感,可以使用 cn build CLI 将合并表编译到项目:

npx cn build --help

⚠️ 动态拼接的类名(如 "p-" + size)无法被编译时检测,与 Tailwind 自身的限制一致,需要用 --safelist 处理。


性能基准

官方 benchmarks(在 58 个开源项目共 144,265 次 cn() 调用上测试):

场景 clsx + tailwind-merge cn 提速
典型组件调用(稳定类名) 320 ns 10 ns 30×
缓存命中(相同类名重复调用) 14 ns 7 ns
数千种重复字符串(真实工作集) 2.4 µs 14 ns 172×
冷渲染 + 大量任意值 3.4 µs 1.1 µs
SSR 冷启动(唯一字符串) 2.3 µs 360 ns 6.4×
首次调用(页面加载) 3.2 ms 0.4 ms

核心原理cn 对重复的调用序列做 argument-identity 缓存(同类调用在第二次起直接跳过计算),在渲染循环中提升效果尤为显著。


典型适用场景

  1. 已有 shadcn/ui 项目:用 npx shadcn@latest migrate cn 一行命令完成迁移,立即获得 30× 提速。
  2. 新项目直接使用:不再需要同时装 clsxtailwind-mergecn 一个包搞定。
  3. 任意 Tailwind CSS 项目:不需要 shadcn/ui 生态,任何框架均可使用。
  4. 高频渲染场景:在 React/Vue 组件的频繁 re-render 中,cn 的缓存机制效果最明显(官方数据 172× 加速)。

坑与注意

⚠️ 需要 Tailwind CSS v4cn 依赖 Tailwind v4 的合并语义。如果项目仍在用 Tailwind v3,应继续使用 tailwind-merge v2,不要升级。

⚠️ CLI 需要 Node 20+npx cn build 等 CLI 工具有 Node 版本要求。

⚠️ 动态类名需 safelist"p-" + size 这种运行时拼接无法被 cn build 检测,与 Tailwind 自身限制相同,请用 --safelist 配置。

⚠️ 不支持 experimentalParseClassName:如果你依赖 tailwind-merge 的这个实验性 API,cn 暂不支持。

⚠️ 仅合并,不做条件拼接以外的处理cn 本质是 clsx + tailwind-merge 的融合,不是功能增强。如果你需要 clsx 的数组/对象以外的特殊语法(如 clsx/lite),cn/lite 出口提供纯字符串版本。

⚠️ Bundle 体积:虽然比 clsx + tailwind-merge 双包小,但 26KB minified 仍需评估是否对极简项目可接受。


与同类对比

方案 依赖数 性能 API 兼容性 适用场景
cn 0 30×(组件调用) 完整兼容 clsx + twMerge 强烈推荐,所有 Tailwind 项目
tailwind-merge v2 0 中等 独立(无 clsx 功能) 需要单独合并功能时
clsx + tailwind-merge 2 基准 完整 暂时不想迁移的存量项目
clsx(单独) 1 最快(仅拼接) 仅条件拼接,无冲突解决 完全不需要类合并时
Tailwind Variants 组件变体专用 需要定义组件变体体系时

一句话推荐结论

如果你的项目同时用 clsxtailwind-merge(也就是大多数使用 cn() 封装的项目),cn 是毫无犹豫的升级选择:零配置迁移、30 倍提速、零新增依赖,今天就可以跑。