抄 Claude 的界面?这5个组件值得你今晚就动手

大多数人做 AI 聊天界面,第一步就做错了——他们在想"功能",Claude 在想"感觉"。

你有没有注意到,用 Claude 的时候有一种说不清楚的"顺滑感"?消息出来的方式、输入框的反馈、空白页的引导……每一处都克制,但每一处都让你觉得"对,就该这样"。这不是偶然,是有人在背后做了大量有意识的设计决策。

好消息是:有人把这套设计系统拆解开源了。

open-claude-design 是 GitHub 上一个复现 Claude 界面组件的开源项目,MIT 协议,可以直接商用。我花了 2 小时跑通环境,把所有组件翻了一遍,筛出了 5 个最值得"抄"进你自己项目的组件——本文就是这次探索的完整记录。

---

一、为什么 Claude 的界面"感觉就是不一样"

AI 产品的界面同质化已经到了一个荒谬的程度:左边侧边栏、右边对话区、底部输入框,连配色都在互相抄。

但 Claude 的界面在这堆产品里显得格外"安静"。没有大量的按钮、没有功能入口轰炸,就连消息气泡的圆角弧度都比别人小一点点——这种克制感反而带来了更强的专注体验。

这背后是 Anthropic 设计团队有意识构建的一套交互语言:信息密度适中、动效有目的性、每一个元素存在都有理由

open-claude-design 这个项目做的事情就是把这套语言拆解出来,用 React + Tailwind 复现成可独立使用的组件库。项目目前在 GitHub 上保持活跃更新,采用 MIT 协议,意味着你可以直接把它的代码用进商业项目里。

---

二、2小时跑起来的完整过程(含踩坑记录)

先说结论:整体不难,但有几个坑会让你白白浪费半小时

克隆与安装(约15分钟)

git clone https://github.com/open-claude-design/open-claude-design.git

cd open-claude-design

npm install

第一个坑在这里就出现了——Node 版本

项目要求 Node >= 18.0,但如果你本地还挂着 16.x 的老版本(很多人的 Mac 上都是),npm install 会在某个原生模块上报错,错误信息指向 sharp,让人一头雾水。

解决方式很简单:

nvm use 18

或者

nvm install 18 && nvm use 18

本地启动(约5分钟)

npm run dev

第二个坑:样式未加载。第一次打开 localhost:3000,你可能看到一片白色无样式的 HTML。原因是 Tailwind 的 JIT 模式在冷启动时需要额外几秒编译。等 10 秒刷新,样式就全回来了。不要慌,也不要去改配置。

避坑速查表

| 问题 | 原因 | 解决方案 | | npm installsharp 错误 | Node 版本 < 18 | nvm use 18 | | 首次启动样式不显示 | Tailwind JIT 冷启动延迟 | 等 10 秒后刷新页面 | | 热更新不生效 | 文件路径含中文或空格 | 把项目放到纯英文路径下 | | 字体加载慢 | 默认走 Google Fonts CDN | 在 _document.tsx 里换成本地字体或国内 CDN |

跑通之后,你会看到一个完整的仿 Claude 界面在本地运行。那一刻确实有点奇妙——和真正的 Claude 放在一起截图,普通用户很难分辨。

---

三、最值得"抄"的5个组件

1. 消息气泡的打字机动效

解决了什么问题: AI 回复如果一次性渲染出来,用户会感觉"突兀",像是在看一堵文字墙。打字机效果让信息"流动"起来,符合对话的自然节奏,同时给用户一个"AI 正在思考"的心理暗示。

有 UX 研究表明,流式输出相比批量输出能显著降低用户的"等待焦虑感"——因为你看到内容在动,就不会觉得在干等。

核心实现(CSS + JS,约18行):
/ 光标闪烁动效 /

@keyframes blink {

0%, 100% { opacity: 1; }

50% { opacity: 0; }

}

.typing-cursor::after {

content: '▋';

animation: blink 1s step-end infinite;

margin-left: 2px;

}

// 打字机逻辑核心

function typewriter(text, setter, speed = 20) {

let index = 0;

const timer = setInterval(() => {

setter(text.slice(0, index + 1));

index++;

if (index >= text.length) clearInterval(timer);

}, speed);

}

适合嵌入哪类项目: 所有 AI 对话类应用。这个组件是优先级最高的,没有之一。

---

2. 侧边栏对话历史折叠逻辑

解决了什么问题: 对话历史多了之后,侧边栏会变成一个信息垃圾堆。Claude 的做法是按时间分组(今天、昨天、过去7天、更早),并且在折叠状态下只显示标题前20个字,悬停才展开完整内容。 关键实现思路: 这不是一个复杂的算法,但分组逻辑需要注意:用 date-fns 做时间计算,而不是手写 timestamp 比较,否则跨时区会出问题。
import { isToday, isYesterday, subDays, isAfter } from 'date-fns';

function groupConversations(conversations) {

return {

today: conversations.filter(c => isToday(new Date(c.updatedAt))),

yesterday: conversations.filter(c => isYesterday(new Date(c.updatedAt))),

lastWeek: conversations.filter(c =>

isAfter(new Date(c.updatedAt), subDays(new Date(), 7)) &&

!isToday(new Date(c.updatedAt)) &&

!isYesterday(new Date(c.updatedAt))

),

};

}

适合嵌入哪类项目: 任何需要管理多轮对话历史的应用,包括客服系统、AI 写作工具。

---

3. 代码块的一键复制 + 语言标签

解决了什么问题: 这是一个"小而美"的设计——代码块右上角显示语言类型(pythonjavascript 等),同时有一个复制按钮,点击后变成"已复制"并在 2 秒后复原。

这个交互逻辑看起来简单,但很多开发者自己实现时会踩一个坑:复制按钮的状态重置没有清理副作用,导致组件卸载后 setTimeout 还在跑,控制台报 warning。

项目里的实现用 useRef 存储 timer id 并在 useEffect 的清理函数里 clearTimeout,这个细节值得直接抄。

适合嵌入哪类项目: 所有涉及代码展示的 AI 应用,尤其是编程助手类产品。

---

4. 输入框的自适应高度 + 快捷键提示

解决了什么问题: 固定高度的