mcpField
N
nexus-ui

nexus-ui

github.com/victorcodess设计与 UI13254 次安装19 周前更新
代码仓库

关于 nexus-ui

Nexus UI 是用于构建 AI 界面的开源 React 组件库,面向需要聊天、流式输出和多模态界面的开发者。组件通过 shadcn registry 以源代码形式安装,基于 Tailwind CSS v4 和 Radix UI。

主要功能

  1. 01提供聊天与提示词输入组件
  2. 02支持模型选择和提示建议
  3. 03提供附件预览与管理界面
  4. 04包含消息、线程和引用组件
  5. 05呈现工具调用与推理步骤状态

适用场景

  1. 01搭建 AI 聊天输入与消息界面
  2. 02在对话中显示附件和引用来源
  3. 03展示工具运行、推理和加载状态

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/victorcodess/nexus-ui --skill nexus-ui

安装后在 Claude Code 中输入/nexus-ui确认已加载。

详细介绍

Nexus UI

用于构建 AI 驱动界面的开源组件库。为聊天、流式传输和多模态体验打造的可组合、可复制粘贴的基础组件,基于 React、Tailwind CSS v4 和 Radix UI 构建。

组件通过 shadcn 注册表分发,并以源代码的形式安装到用户的项目中。

IMPORTANT: 请根据项目的 packageManager,使用项目的包运行器执行 CLI 命令:npx shadcn@latest、pnpm dlx shadcn@latest 或 bunx --bun shadcn@latest。

安装

1. 添加注册表

将 Nexus UI 注册表添加到项目的 components.json 中:

{
  "registries": {
    "@nexus-ui": "https://nexus-ui.dev/r/{name}.json"
  }
}
2. 添加组件
npx shadcn@latest add @nexus-ui/prompt-input
npx shadcn@latest add @nexus-ui/model-selector
npx shadcn@latest add @nexus-ui/suggestions
npx shadcn@latest add @nexus-ui/attachments
npx shadcn@latest add @nexus-ui/message
npx shadcn@latest add @nexus-ui/thread
npx shadcn@latest add @nexus-ui/citation
npx shadcn@latest add @nexus-ui/reasoning
npx shadcn@latest add @nexus-ui/text-shimmer
npx shadcn@latest add @nexus-ui/image
npx shadcn@latest add @nexus-ui/feedback-bar
npx shadcn@latest add @nexus-ui/toaster
npx shadcn@latest add @nexus-ui/chain-of-thought
npx shadcn@latest add @nexus-ui/tool
npx shadcn@latest add @nexus-ui/questions

也可以通过 URL 直接安装(无需配置注册表):

npx shadcn@latest add https://nexus-ui.dev/r/prompt-input.json

默认情况下,组件会安装到 components/nexus-ui/。

前置条件
  • React 19+
  • Tailwind CSS v4
  • TypeScript
  • 已初始化 shadcn/ui(npx shadcn@latest init)

可用组件

组件注册表名称说明
提示词输入框prompt-input可组合的聊天输入框,带有自动调整大小的文本区域和操作插槽
模型选择器model-selector用于选择 AI 模型的下拉菜单,支持单选组、子菜单和自定义条目
建议suggestions用于引导用户输入的提示词建议标签
附件attachments用于聊天输入和消息的可组合文件附件,支持预览、变体和上传接线
消息message聊天消息布局,支持 Markdown、可选头像、操作和附件
对话线程thread可滚动的聊天线程,支持贴底滚动和跳转到底部的控件
引用citation内联来源引用,支持悬停预览和多来源轮播
推理reasoning可折叠的模型推理轨迹,带有适配流式传输的标签和 Markdown 正文
文本闪烁效果text-shimmer动画闪烁文本,用于加载、工具运行及其他进行中的 UI
图像image用于 URL、base64 和字节载荷的图像渲染器,支持预览、加载器、灯箱和操作插槽
反馈栏feedback-bar反馈提示栏,可对单条消息或整个线程评分,并带有操作和关闭插槽
通知提示toaster由 Sonner 提供支持的无头 Toast 通知,支持按变体设置样式以及自定义操作/取消控件
思维链chain-of-thought结构化的多步思考时间线,支持步骤状态、可选的可展开输出,以及步骤完成时自动关闭
工具tool可感知状态的工具调用 UI,支持 JSON 输入/输出代码块(pending、ready、running、completed、error)
问题questions后续澄清问题,支持单选或多选、轮播导航和批量提交

组件 API

每个部分都采用相同的大纲:导入 → 组成部分 → 根属性 → 属性和钩子 → 用法说明 → 示例(适用时提供简短代码片段)。

提示词输入

可组合的聊天输入框:自动增高的文本区域,以及用于附件、发送和类似控件的底部操作栏。

导入:

import {
  PromptInput,
  PromptInputTextarea,
  PromptInputActions,
  PromptInputActionGroup,
  PromptInputAction,
} from "@/components/nexus-ui/prompt-input";

组成部分:

部分用途
PromptInput根布局:带边框的卡片,包含文本区域和操作控件。
PromptInputTextarea自动调整大小的文本区域(最大高度约为 160px),位于 shadcn ScrollArea 内。
PromptInputActions底部栏;使用 justify-between 分隔左右两组操作控件。
PromptInputActionGroup操作控件的水平分组(gap-2)。
PromptInputAction单个控件的插槽;支持 asChild,并可通过 tooltip(字符串或对象)启用内置工具提示。

根组件属性: PromptInput 上的可选 onSubmit(value: string),用于在 PromptInputTextarea 中按 Enter 提交(Shift+Enter 换行),以及常规 DOM 属性 / className。

属性和钩子: 每个组成部分都接受 className。PromptInputTextarea 接受标准文本区域属性。PromptInputAction 支持 asChild 和 tooltip?: string | { content?: string; side?: "top" | "right" | "bottom" | "left"; shortcut?: string }(缺少 content 时不会渲染工具提示)。没有上下文钩子。

使用说明: 将附件 / 工具放在第一个 PromptInputActionGroup 中,将发送控件放在第二个分组中,以便通过 justify-between 将它们分开。建议在 Button 外层使用 PromptInputAction asChild,而不是直接将 PromptInputAction 用作可点击元素。

示例:

<PromptInput>
  <PromptInputTextarea placeholder="Ask anything..." />
  <PromptInputActions>
    <PromptInputActionGroup>
      <PromptInputAction asChild>
        <Button variant="ghost" size="icon" className="rounded-full">
          <Paperclip />
        </Button>
      </PromptInputAction>
    </PromptInputActionGroup>
    <PromptInputActionGroup>
      <PromptInputAction asChild>
        <Button size="icon" className="rounded-full">
          <ArrowUp />
        </Button>
      </PromptInputAction>
    </PromptInputActionGroup>
  </PromptInputActions>
</PromptInput>
模型选择器

用于选择模型(或类似值)的下拉菜单,基于 Radix DropdownMenu 构建,并可选用 items 元数据提供标签、描述和图标。

导入:

import {
  ModelSelector,
  ModelSelectorPortal,
  ModelSelectorTrigger,
  ModelSelectorContent,
  ModelSelectorGroup,
  ModelSelectorLabel,
  ModelSelectorItemTitle,
  ModelSelectorItemDescription,
  ModelSelectorItemIcon,
  ModelSelectorItemIndicator,
  ModelSelectorItem,
  ModelSelectorCheckboxItem,
  ModelSelectorRadioGroup,
  ModelSelectorRadioItem,
  ModelSelectorSeparator,
  ModelSelectorSub,
  ModelSelectorSubTrigger,
  ModelSelectorSubContent,
} from "@/components/nexus-ui/model-selector";

组成部分:

部分用途
ModelSelector根级提供者和下拉菜单根组件;管理选择上下文(参见 根组件属性)。
ModelSelectorPortal可选的菜单内容 portal 包装器(在将内容渲染到 portal 中时使用)。
ModelSelectorTrigger打开菜单;设置了 items 时显示所选标签。
ModelSelectorContent菜单表面 / 面板。
ModelSelectorGroup对行进行分组;通常与 ModelSelectorLabel 配合使用。
ModelSelectorLabel组内的分区标题。
ModelSelectorItem通用菜单行。
ModelSelectorItemTitle菜单项的主文本行。
ModelSelectorItemDescription菜单项的次文本行。
ModelSelectorItemIcon菜单项的前置图标插槽。
ModelSelectorItemIndicator选择指示器(例如勾选标记)。
ModelSelectorCheckboxItem复选框样式的菜单项。
ModelSelectorRadioGroup单选组;传入 Radix value / onValueChange。
ModelSelectorRadioItem单选行;支持 title、description、icon、indicator。
ModelSelectorSeparator分区之间的视觉分隔线。
ModelSelectorSub嵌套子菜单容器。
ModelSelectorSubTrigger用于展开子菜单的行。
ModelSelectorSubContent嵌套项的弹出层主体。

根组件属性: ModelSelector 上必须提供 value 和 onValueChange。可选的 items:{ value, title, description?, icon? }[],用于填充触发器文本和内部元数据。其他 Radix 菜单根组件属性均适用,但根组件上的 value / onValueChange 专用于此 API。

属性和钩子: ModelSelectorTrigger 增加了 variant:filled | outline | ghost(默认值为 filled)。选择状态由你的 React 状态(value / onValueChange)管理;除 Radix 行为外,没有其他钩子。

使用说明: 独占选择建议使用 ModelSelectorRadioGroup + ModelSelectorRadioItem;需要多个切换项时使用 ModelSelectorCheckboxItem。使用 ModelSelectorSub / SubTrigger / SubContent 嵌套高级菜单树。较长的菜单建议使用 ModelSelectorGroup、ModelSelectorLabel 和 ModelSelectorSeparator。

示例:

// models: { value: string; title: string; description?: string; icon?: ComponentType<{ className?: string }> }[]
const [model, setModel] = React.useState(models[0].value);

<ModelSelector value={model} onValueChange={setModel} items={models}>
  <ModelSelectorTrigger />
  <ModelSelectorContent align="start">
    <ModelSelectorGroup>
      <ModelSelectorLabel>Select model</ModelSelectorLabel>
      <ModelSelectorRadioGroup value={model} onValueChange={setModel}>
        {models.map((m) => (
          <ModelSelectorRadioItem
            key={m.value}
            value={m.value}
            icon={m.icon}
            title={m.title}
            description={m.description}
          />
        ))}
      </ModelSelectorRadioGroup>
    </ModelSelectorGroup>
  </ModelSelectorContent>
</ModelSelector>
建议项

用于快速提示词的标签,可选择使用动画面板将建议项分组展示。

导入:

import Suggestions, {
  SuggestionList,
  Suggestion,
  SuggestionPanel,
  SuggestionPanelHeader,
  SuggestionPanelTitle,
  SuggestionPanelClose,
  SuggestionPanelContent,
} from "@/components/nexus-ui/suggestions";

组成部分:

组成部分用途
Suggestions根组件;可选的 onSelect(value: string),用于处理标签点击(通过上下文)。
SuggestionList标签的弹性布局列表;orientation 可设为 "horizontal" | "vertical"。
Suggestion标签 Button;variant 可设为 filled | outline | ghost;可选的 value、highlight。
SuggestionPanel包含分组建议项的动画容器。
SuggestionPanelHeader面板内的顶部栏。
SuggestionPanelTitle标题栏中的标题行。
SuggestionPanelClose关闭控件;支持 asChild。
SuggestionPanelContent主体区域;支持 asChild。

根组件属性: Suggestions — 可选的 onSelect(value: string)。SuggestionPanel — 可选的 open(默认值为 true)、onOpenChange、onClose(退出动画结束后运行)。

属性与钩子: 无选择器钩子;通过 onSelect 和 Suggestion 的 Button 属性连接行为。Suggestion 不使用外层的 variant,而是采用上方的 Nexus variant 联合类型。

使用说明: 可组合多个 SuggestionList 区块,也可将列表置于 SuggestionPanel 中,以逐步展示内容。highlight 会弱化标签文本中匹配的子字符串。可在标题栏中使用 SuggestionPanelClose 提供关闭操作。

示例:

// Often paired with prompt state: onSelect((q) => setInput(q))
<Suggestions onSelect={(q) => setInput(q)}>
  <SuggestionList>
    <Suggestion value="Summarize this thread">Summarize this thread</Suggestion>
    <Suggestion value="Draft a reply">Draft a reply</Suggestion>
  </SuggestionList>
</Suggestions>
附件

为提示词或消息行提供受控文件预览:隐藏的文件输入框、可选的窗口级拖放功能,以及每个项目的移除/进度 UI。

导入:

import Attachments, {
  AttachmentTrigger,
  AttachmentList,
  Attachment,
  AttachmentPreview,
  AttachmentRemove,
  AttachmentInfo,
  AttachmentProperty,
  AttachmentProgress,
  AttachmentsDropOverlay,
  useAttachments,
  toAttachmentMeta,
  filesFromDataTransfer,
} from "@/components/nexus-ui/attachments";

组成部分:

组成部分用途
Attachments根级提供程序:隐藏的 <input type="file">、验证、Blob URL 生命周期管理,以及可选的 window 拖放监听器。
AttachmentTrigger打开文件选择器(构建自定义触发器时,可搭配 useAttachments().inputId/标签使用)。
AttachmentList承载各个 Attachment 的水平滚动区域/弹性布局行。
Attachment单个磁贴;传入 attachment: AttachmentMeta;variant 可设为 compact | inline | detailed | pasted。
AttachmentPreview缩略图或类型图标区域(上下文:当前附件)。
AttachmentInfoAttachmentProperty 行的文本列包装器。
AttachmentProperty通过 as="name" | "size" | "kind" 渲染 name、size 或文件 kind。
AttachmentRemove移除当前项目(如果提供了 Attachment 的 onRemove,则调用它)。
AttachmentProgress细进度条;value 范围为 0–100。
AttachmentsDropOverlay拖动期间显示的投影叠加层;variant 可设为 fullscreen | contained。

根组件属性: Attachments 必须传入 attachments 和 onAttachmentsChange。可选属性:accept、multiple(默认值为 true)、maxFiles、maxSize(单个文件的大小上限,单位为字节)、disabled、onFileInputChange、onFilesRejected、windowDrop。

属性与钩子: useAttachments() — 仅可在 <Attachments> 内使用 — 提供 inputRef、inputId、openPicker、appendFiles、isDraggingFile、当前的 attachments、onAttachmentsChange、限制值和 disabled。导出的类型:AttachmentMeta、AttachmentsRejectedFiles、AppendFilesOptions。辅助函数:toAttachmentMeta(file, options?)、用于粘贴/拖放的 filesFromDataTransfer。

使用说明: 在自定义拖放/粘贴处理函数中调用 appendFiles,即可复用原生文件选择器的相同限制。启用 windowDrop 并搭配 AttachmentsDropOverlay,即可显示全应用范围的文件拖放提示。当受控的 attachments 数组中移除项目时,会撤销对应的对象 URL。

示例:

const [items, setItems] = React.useState<AttachmentMeta[]>([]);

<Attachments attachments={items} onAttachmentsChange={setItems} accept="image/*" maxFiles={5}>
  <AttachmentTrigger />
  <AttachmentList>
    {items.map((meta, index) => (
      <Attachment
        key={meta.url ?? `${meta.name}-${index}`}
        attachment={meta}
        variant="compact"
        onRemove={() => setItems(items.filter((_, i) => i !== index))}
      />
    ))}
  </AttachmentList>
</Attachments>
消息

用户和助手消息行,包含可选头像、Markdown 正文(通过 Streamdown)和末尾操作。

导入:

import {
  Message,
  MessageStack,
  MessageContent,
  MessageMarkdown,
  MessageActions,
  MessageActionGroup,
  MessageAction,
  MessageAvatar,
} from "@/components/nexus-ui/message";

组成部分:

部分用途
Message根组件;必填 from:"user" | "assistant"(布局 + role="article")。
MessageStack用于在一条消息内纵向堆叠多个区块。
MessageContent气泡 / 内容包装器(用户和助手的样式不同)。
MessageMarkdown使用 Streamdown 插件(代码、数学公式、mermaid、CJK)渲染 Markdown。
MessageActions操作行容器。
MessageActionGroup将操作按钮分组。
MessageAction单个操作;支持 asChild,并可通过 tooltip(字符串或对象)启用内置提示框。
MessageAvatar头像列;包含 src、可选的 fallback、alt、size、delayMs。

根组件属性: Message 上必填 from:"user" | "assistant"。标准的 HTMLAttributes<HTMLDivElement> 适用于 article 包装器。除非传入 aria-label 或 aria-labelledby,否则默认 aria-label 为 "User message" 或 "Assistant message"。

属性和 Hook: 不导出上下文 Hook。后代组件(MessageStack、MessageContent、MessageActions 等)从内部上下文读取 from(在 Message 外部使用时,回退为 assistant)。MessageMarkdown 接受 Streamdown 属性(ComponentProps<typeof Streamdown>):例如,通过 children 传入 Markdown,可选的 components 会与内置的 code / table / inlineCode 默认值合并,还可传入 className。MessageAction 支持 asChild(Radix Slot)和 tooltip?: string | { content?: string; side?: "top" | "right" | "bottom" | "left"; shortcut?: string }(缺少 content 时不渲染提示框)。MessageAvatar:必填 src;可选 alt、fallback、delayMs、size、className。

使用说明: 注册表安装会在 message.tsx 旁添加 codeblock.tsx。手动安装时,合并注册表条目中的 Streamdown 相关 CSS。建议在 Button 外使用 MessageAction asChild 来创建操作。

示例:

<Message from="assistant">
  <MessageAvatar src="https://github.com/shadcn.png" fallback="AI" />
  <MessageStack>
    <MessageContent>
      <MessageMarkdown>Here is **markdown** and `inline code`.</MessageMarkdown>
    </MessageContent>
    <MessageActions>
      <MessageActionGroup>
        <MessageAction asChild>
          <Button type="button" variant="ghost" size="sm">
            Copy
          </Button>
        </MessageAction>
      </MessageActionGroup>
    </MessageActions>
  </MessageStack>
</Message>

<Message from="user">
  <MessageContent>
    <MessageMarkdown>Short user reply</MessageMarkdown>
  </MessageContent>
</Message>
线程

封装 use-stick-to-bottom,用于创建可滚动的消息列表,使其始终停留在新内容处,并在用户向上滚动时显示浮动控件。

导入:

import {
  Thread,
  ThreadContent,
  ThreadScrollToBottom,
} from "@/components/nexus-ui/thread";

组成部分:

部分用途
Thread根组件;转发 StickToBottom 属性(resize、initial、弹簧选项等)。
ThreadContent消息的可滚动列(flex flex-col gap-*)。
ThreadScrollToBottom当未处于底部时显示的按钮(或 asChild);调用 scrollToBottom。

根组件属性: Thread 是带有默认值 resize="smooth" 和 initial="smooth" 的 StickToBottom。可选的 StickToBottomOptions:resize、initial、mass、damping、stiffness、targetScrollTop。还包括 instance(预先创建的 stick-to-bottom 实例)、contextRef,以及外层 div 上的标准 HTMLAttributes。

属性和 Hook: 在 Thread 内部,使用 use-stick-to-bottom 中的 useStickToBottomContext() 获取 isAtBottom、scrollToBottom、state 等。ThreadScrollToBottom 内部使用该上下文;如果已经处于底部,则返回 null。它接受 asChild 和标准按钮 HTML 属性(未设置 asChild 时,会渲染带样式的 <button>)。

使用说明: 将 ThreadContent 和 ThreadScrollToBottom 作为同级组件放在 Thread 内部。为 Thread 设置有界高度(例如 h-full / min-h-*),以定义滚动区域。

示例:

<Thread className="min-h-[480px]">
  <ThreadContent>
    {messages.map((m) => (
      <Message key={m.id} from={m.role === "user" ? "user" : "assistant"}>
        <MessageContent>
          <MessageMarkdown>{m.text}</MessageMarkdown>
        </MessageContent>
      </Message>
    ))}
  </ThreadContent>
  <ThreadScrollToBottom />
</Thread>
引用

可组合的内联引用标记,带有 Radix HoverCard 预览。多个 URL 会在面板内使用轮播(CitationCarousel*)。

导入:

import {
  Citation,
  CitationTrigger,
  CitationContent,
  CitationSource,
  CitationSourcesBadge,
  CitationItem,
  CitationFavicon,
  CitationSiteName,
  CitationCarousel,
  CitationCarouselContent,
  CitationCarouselHeader,
  CitationCarouselItem,
  CitationCarouselPrev,
  CitationCarouselNext,
  CitationCarouselPagination,
  CitationCarouselIndex,
} from "@/components/nexus-ui/citation";

辅助函数: resolveCitationSources、resolveCitationSource、parseCitationUrl、rootDomainSiteName,类型 CitationSourceInput、ResolvedCitation。

组成部分:

部分用途
Citation根 HoverCard;管理已解析的来源和轮播索引状态。
CitationTrigger标记触发器;单个来源渲染为链接,多个来源渲染为 span + “+N”。
CitationContent悬浮面板表面(默认 align="center"、sideOffset={4})。
CitationCarouselShadcn Carousel;将 setApi 接入引用上下文。
CitationCarouselContent / Item幻灯片;每个 CitationCarouselItem 都需要 index。
CitationCarouselPrev / Next / Index / Pagination / Header导航控件。
CitationItem默认预览正文(标题、描述、CitationSource)或自定义子项;锚点指向 href。
CitationSource页脚行:网站图标 + 网站名称。
CitationFavicon / CitationSiteName从当前轮播项或 CitationItem 作用域解析。
CitationSourcesBadge堆叠的网站图标 + “N 个来源”(或自定义 label);用于工具栏,而非悬浮标记。

根组件属性: 在 Citation 上,必须提供 citations: CitationSourceInput[](url,以及可选的 title、description)。其他所有属性均省略 HoverCard 的 children 并透传;可选的 children 用于组合触发器和内容。若 citations 为空,则渲染 null。根卡片的 openDelay / closeDelay 设为 50。

属性和 Hook: 不导出 Hook;CitationItem、CitationFavicon 等需要祖先 Citation,且(对于轮播内的项目)需要匹配的、带有 index 的 CitationCarouselItem。CitationTrigger:可选的 label、showFavicon(默认 true)、showSiteName(默认 true)。CitationCarouselItem:必需的 index: number。CitationItem:可选的 showTitle、showDescription、showSource(默认均为 true);href 默认为已解析的 URL。CitationSourcesBadge:可选的 showFavicons、label。

使用说明: 从 RAG / 搜索工作流构建 citations;如果自行规范化 URL,请使用 resolveCitationSources。对于两个或更多 URL,请在 CitationContent 内放置 CitationCarousel,并为每个索引放置一个 CitationCarouselItem。CitationSourcesBadge 是可选的界面控件,可用于消息标题或操作区,但仍须位于 Citation 下。

示例(单个来源):

<Citation
  citations={[
    {
      url: "https://vercel.com/blog",
      title: "Vercel Blog",
      description: "Product and platform updates.",
    },
  ]}
>
  <CitationTrigger />
  <CitationContent>
    <CitationItem />
  </CitationContent>
</Citation>

示例(多个来源 + 轮播):

const sources = [
  { url: "https://example.com/a", title: "Source A" },
  { url: "https://example.com/b", title: "Source B" },
];

<Citation citations={sources}>
  <CitationTrigger />
  <CitationContent>
    <CitationCarousel>
      <CitationCarouselHeader>
        <CitationSourcesBadge />
        <CitationCarouselPagination>
          <CitationCarouselPrev />
          <CitationCarouselIndex />
          <CitationCarouselNext />
        </CitationCarouselPagination>
      </CitationCarouselHeader>
      <CitationCarouselContent>
        {sources.map((_, index) => (
          <CitationCarouselItem key={index} index={index}>
            <CitationItem />
          </CitationCarouselItem>
        ))}
      </CitationCarouselContent>
    </CitationCarousel>
  </CitationContent>
</Citation>
推理

基于 shadcn Collapsible 构建的可折叠“思考”区块:触发器标签会从流式状态文案切换为耗时摘要,正文通过 Streamdown 渲染 Markdown。

导入:

import {
  Reasoning,
  ReasoningTrigger,
  ReasoningContent,
} from "@/components/nexus-ui/reasoning";

组成部分:

组成部分用途
Reasoning根级 Provider 和可折叠根组件;管理打开状态与 isStreaming,并生成上下文相关的触发器标签(Thinking… → Thought for N seconds)。
ReasoningTrigger包含脑图标、标签文本(流式状态下会在 span 上使用 tw-shimmer 工具类)和在打开时旋转的箭头图标的行。
ReasoningContent展开后使用 Streamdown 渲染 Markdown,并应用弱化样式和左侧边框条。需要 children: string(Markdown 源文本)。

根组件属性: 在 Reasoning 上,isStreaming 为可选项(默认 false),用于在流式传输期间自动打开,并在流式传输结束时自动关闭和记录耗时;open / defaultOpen / onOpenChange 为可选的受控属性(继承可折叠组件的语义,但 Reasoning 的类型省略了 Radix 的 open/defaultOpen/onOpenChange,改用列出的属性)。还接受其余与 Collapsible 兼容的属性以及 className。

属性与钩子: 不导出钩子(仅使用内部上下文)。ReasoningTrigger/ReasoningContent 必须是 Reasoning 的后代。通过 Registry 安装会引入 collapsible、streamdown、Hugeicons 包、@import "tw-shimmer",以及用于可折叠高度动画的关键帧。

使用说明: 根据聊天传输层或部分流切换 isStreaming。省略 ReasoningTrigger 的子元素即可使用计算出的标签;只有在兼顾无障碍要求时,才传入子元素以覆盖可见标签。

示例:

<Reasoning isStreaming={status === "streaming"}>
  <ReasoningTrigger />
  <ReasoningContent>{reasoningMarkdownString}</ReasoningContent>
</Reasoning>
文本微光

单个基础组件,可在文本上动画显示移动的高亮(bg-clip-text + 注入的 @keyframes)。除了 @/lib/utils,不需要其他 UI 依赖。

导入:

import { TextShimmer } from "@/components/nexus-ui/text-shimmer";

组成部分: 单个组件 — TextShimmer。可选的多态根元素,通过 as 指定(默认 "span")。

根组件属性: duration — 高亮扫过的时长(秒,默认 2.5);repeatDelay — 下次扫过前的暂停时间(默认 0);spread — 高亮相对于中心的宽度(百分点,约束在 5–45 之间,默认 20);angle — 添加到渐变轴的角度(默认 0);color — 覆盖光束的色标颜色;invert — 翻转默认的明暗光束对比度;以及标准 HTML 属性、className 和 style。子元素为标签文本/节点树。

属性与钩子: 无上下文。通过 useId 为每个实例注入唯一的 @keyframes 名称。

使用说明: 建议用于较短的状态文本(“Running tools…”)。如果边缘颜色应继承自排版样式,可在包装元素上配合弱化的 text-muted-foreground 使用。

示例:

<TextShimmer repeatDelay={0.5}>Running tool calls</TextShimmer>
图像

适用于多模态模型的可组合图像卡片:接受 src、base64 或 uint8Array(以及 mediaType),将内容包裹在 Radix Dialog 根组件中,以便通过灯箱查看,并提供加载器和绝对定位的操作区域。

导入:

import {
  Image,
  ImagePreview,
  ImageLightbox,
  ImageLightboxOverlay,
  ImageLightboxPreview,
  ImageLightboxClose,
  ImageLoader,
  ImageActions,
  ImageActionGroup,
  ImageAction,
} from "@/components/nexus-ui/image";

组成部分:

部分用途
ImageDialog 内的根 div;解析 src、来自 base64 的数据 URL,或来自 uint8Array 的对象 URL;提供上下文;默认子项为 ImagePreview。
ImagePreview缩略图;如果 src 已解析,则将 <img> 包裹在 Dialog Trigger 中;内容为空时显示 ImageLoader。
ImageLightboxDialog.Portal 包装器。
ImageLightboxOverlay模态背景遮罩。
ImageLightboxPreviewDialog.Content,包含大尺寸 <img>(object-contain)和屏幕阅读器标题。
ImageLightboxClose视觉隐藏的关闭控件(sr-only)。
ImageLoader脉冲骨架屏;通过上下文反映错误状态。
ImageActions绝对定位的操作栏;align:inline-start | inline-end | block-start | block-end。
ImageActionGroup / ImageAction分组控件;ImageAction 支持 asChild + Slot,并可通过 tooltip(字符串或对象)使用内置工具提示。

根组件属性: 在 Image 上传入 src、base64 或 uint8Array 之一;可选传入 mediaType、alt;还可传入 Radix 对话框根组件属性(open、defaultOpen、onOpenChange、modal)以及常规 div HTML 属性 / className。

属性与钩子: 仅使用内部上下文(不导出钩子)。嵌套部分必须位于 Image 下。

使用说明: 在 Image 上省略 children 可使用默认预览。将 ImageLightbox* 作为根卡片的同级元素组合使用(文档中的常见模式),这样点击预览即可打开模态框。使用 ImageActions + ImageAction asChild 包裹 Button 以进行下载或分享;在 ImageAction 上添加 tooltip 可设置标签、显示位置和可选快捷键。

示例(最简):

<Image base64={modelImageBase64} alt="Generated scene">
  <ImagePreview />
  <ImageLightbox>
    <ImageLightboxOverlay />
    <ImageLightboxPreview />
    <ImageLightboxClose />
  </ImageLightbox>
</Image>
反馈栏

用于消息或线程中“这有帮助吗?”类流程的紧凑栏:左侧放置 提示词(标签),右侧放置 操作(例如点赞),并可选添加 关闭列。FeedbackBarAction 可通过 asChild 包裹实际按钮,并显示带可选 键盘快捷键标记的 工具提示(shadcn Tooltip + Kbd)。

导入:

import {
  FeedbackBar,
  FeedbackBarContent,
  FeedbackBarPrompt,
  FeedbackBarLabel,
  FeedbackBarActions,
  FeedbackBarAction,
  FeedbackBarClose,
} from "@/components/nexus-ui/feedback-bar";

组成部分:

部分用途
FeedbackBar根 role="group" 条;默认高度为 h-12,宽度占满(最大约 28rem),带边框的 rounded-[12px] 表面。
FeedbackBarContent填满栏的 justify-between 弹性行。
FeedbackBarPrompt左侧区域(默认 pl-4),用于放置文案和前置内容。
FeedbackBarLabel主要提示词文本(font-[350])。
FeedbackBarActions右侧控件组区域(gap-1.5)。
FeedbackBarAction单个控件容器;支持 asChild + Slot;可选 tooltip:string 或 { content?, side?, shortcut? }。
FeedbackBarClose右侧窄栏,带前置边框;使用 FeedbackBarAction + asChild 包裹宿主 div;将关闭 Button/IconButton 作为子项传入。

根组件属性: 每个部分都使用普通的 HTMLAttributes;插槽部分接受 className。FeedbackBarAction / FeedbackBarClose:参见上文的工具提示说明。

属性与钩子: 无上下文。对于设置了 tooltip.content 的操作,每个操作都会单独渲染一个本地 TooltipProvider。

使用说明: 将图标按钮放入 FeedbackBarAction asChild 中,以提供合适的点击区域。若要对应实际的键盘操作,建议在 tooltip 中使用 shortcut。

示例:

<FeedbackBar>
  <FeedbackBarContent>
    <FeedbackBarPrompt>
      <FeedbackBarLabel>Was this response helpful?</FeedbackBarLabel>
    </FeedbackBarPrompt>
    <FeedbackBarActions>
      <FeedbackBarAction asChild tooltip={{ content: "Helpful", shortcut: "⌘Y" }}>
        <button type="button" aria-label="Helpful">…</button>
      </FeedbackBarAction>
    </FeedbackBarActions>
    <FeedbackBarClose>
      <button type="button" aria-label="Dismiss">…</button>
    </FeedbackBarClose>
  </FeedbackBarContent>
</FeedbackBar>
Toaster

由 Sonner 驱动的无头 Toast 通知,支持按变体设置样式以及自定义操作/取消控件。使用 next-themes 支持浅色/深色/系统主题。导出 Toaster(在根布局中挂载一次)和带有便捷辅助方法及 toast.dismiss 的 toast 对象。

导入:

import { Toaster, toast } from "@/components/nexus-ui/toaster";

组成部分/API:

导出项用途
Toaster使用 toastOptions={{ unstyled: true }} 渲染 <Sonner />,并通过 useTheme() 获取主题;展开传入额外的 ToasterProps。
toast.custom构建完全自定义的内容(title、可选的 description、variant、icon、action、cancel、Sonner 计时/选项)。
toast.default / success / info / warning / error / loading简写形式 (title, options?),委托给 toast.custom。
toast.dismiss转发到 Sonner 的关闭 API。

根级属性:Toaster 支持标准 Sonner 属性(position、duration、expand 等),以及 Sonner 提供的 className 合并行为。

**属性与钩子:**需要在渲染 Toaster 的布局上方提供 next-themes 中的 ThemeProvider,以便 useTheme() 正常解析。Toast 内容使用 shadcn 的 Button 作为操作/取消/关闭按钮。

**使用说明:**将 <Toaster /> 放在应用外框旁边(例如 layout.tsx)。快速反馈时优先使用 toast.success("Copied");需要取消按钮或自定义图标时使用 toast.custom(使用 icon: null 可隐藏默认图标)。

示例:

// layout.tsx
<Toaster position="bottom-right" />

// anywhere client-side
toast.success("Saved");
toast.error("Something went wrong", { description: "Try again.", duration: 5000 });
Chain of Thought

用于工具/推理步骤的结构化时间线:一个根级可折叠区域跟踪所有子步骤的状态;活动标签可选择显示闪烁效果(通过 tw-shimmer);useOnChange 会在步骤转换时控制自动展开/关闭。

导入:

import {
  ChainOfThought,
  ChainOfThoughtTrigger,
  ChainOfThoughtContent,
  ChainOfThoughtStep,
  ChainOfThoughtStepTitle,
  ChainOfThoughtStepContent,
  ChainOfThoughtComplete,
  type ChainOfThoughtStepStatus,
} from "@/components/nexus-ui/chain-of-thought";

组成部分:

组成部分用途
ChainOfThought根级 Collapsible 和步骤上下文注册表;属性 autoCloseOnAllComplete(默认值为 true)会在每个步骤都为 completed 时关闭。
ChainOfThoughtTrigger带可选图标/标签和箭头的标题行;任务进行期间标签会闪烁。
ChainOfThoughtContent用于容纳 ChainOfThoughtStep 列表的主体容器。
ChainOfThoughtStep每个步骤的 Collapsible;status 控制注册与闪烁;hasContent 和 autoCloseOnComplete 会自动管理展开状态。
ChainOfThoughtStepTitle带图标和标签的行;存在可展开内容时会变为 CollapsibleTrigger(也可强制设置 collapsible)。
ChainOfThoughtStepContent步骤的可展开输出区域。
ChainOfThoughtComplete步骤之后可选的页脚行(“所有步骤均已完成”)。

**根级属性:**请参阅源代码类型:根级和步骤支持受控的 open / defaultOpen / onOpenChange;ChainOfThoughtStepStatus 为 "pending" | "active" | "completed" | "error"。

**属性与钩子:**仅使用内部上下文。通过注册表安装时会包含 lib/use-on-change.ts。

**使用说明:**若要支持展开/折叠,请为 hasContent 提供每个步骤稳定的可视内容。与流式传输/工具事件配合使用时,请在每个步骤上更新 status。

示例(结构):

<ChainOfThought>
  <ChainOfThoughtTrigger>Chain of thought</ChainOfThoughtTrigger>
  <ChainOfThoughtContent>
    <ChainOfThoughtStep status="completed">
      <ChainOfThoughtStepTitle icon={…} label="Search the web" />
    </ChainOfThoughtStep>
    <ChainOfThoughtStep status="active" hasContent>
      <ChainOfThoughtStepTitle icon={…} label="Read results" />
      <ChainOfThoughtStepContent>…</ChainOfThoughtStepContent>
    </ChainOfThoughtStep>
  </ChainOfThoughtContent>
</ChainOfThought>
工具

用于单次工具调用的状态感知型可折叠 UI:状态驱动的标题栏(图标 + 徽标)、JSON 输入,以及通过 Shiki 代码块展示的可选输出。可与 Vercel AI SDK 的工具部分状态直接对应。

导入:

import {
  Tool,
  ToolTrigger,
  ToolContent,
  ToolInput,
  ToolOutput,
  type ToolStatus,
} from "@/components/nexus-ui/tool";

组成部分:

部分用途
Tool根 Collapsible;必需的 status(pending | ready | running | completed | error)用于设置 CSS 变量和徽标/图标样式上下文。
ToolTrigger标题行;必需的 name(工具标签),以及状态徽标和箭头。
ToolContentToolInput / ToolOutput 区块的主体。
ToolInput渲染格式化后的 JSON(或字符串)输入区块。
ToolOutput当 status 属于 showWhen 时渲染输出(默认 ["completed"]);发生 error 时显示 errorText,以及可选的负载代码块。

根组件属性: Tool 转发 Collapsible 属性;ToolOutput 接受 showWhen?: ToolStatus[] 和 errorText?: string。

属性与钩子: 仅使用内部上下文。注册表安装会在 tool.tsx 旁添加 codeblock-new.tsx 和 lib/shiki/highlighter.ts。

使用说明: 根据工具的生命周期设置 status(例如,将 AI SDK 的 tool-invocation 状态映射过来)。需要在失败时显示输出时,将 ToolOutput 与 showWhen={["completed", "error"]} 配合使用。

示例:

<Tool status="running">
  <ToolTrigger name="search_web" />
  <ToolContent>
    <ToolInput payload={{ query: "nexus ui" }} />
    <ToolOutput payload={result} showWhen={["completed", "error"]} errorText="Search failed" />
  </ToolContent>
</Tool>
问题

用于聊天中后续澄清的卡片 UI:传入 items 元数据,使用 QuestionOption / QuestionOther 组合 Question 幻灯片,通过 QuestionsCarousel* 导航,并通过 onSubmit 收集答案。

导入:

import {
  Questions,
  Question,
  QuestionOptions,
  QuestionOption,
  QuestionOther,
  QuestionsTitle,
  QuestionsHeader,
  QuestionsFooter,
  QuestionsSkip,
  QuestionsSubmit,
  QuestionsDismiss,
  QuestionsCarousel,
  QuestionsCarouselContent,
  QuestionsCarouselItem,
  QuestionsCarouselPagination,
  QuestionsCarouselPrev,
  QuestionsCarouselNext,
  QuestionsCarouselIndex,
  type QuestionsSubmission,
  type QuestionInput,
} from "@/components/nexus-ui/questions";

组成部分:

部分用途
Questions根 Card + provider;必需的 items: QuestionInput[];可选的 autoAdvance(默认 true)、onSubmit、onSkip、onDismiss。
QuestionsHeader / QuestionsTitle / QuestionsDismiss顶部区域和关闭控件。
QuestionsCarousel*用于多问题流程的 Shadcn Carousel 封装(Prev / Next / Index / Pagination)。
Question单张幻灯片;注册 id、type(single | multiple)、prompt、required。
QuestionOptions选项行的布局容器。
QuestionOption可选择的行(根据问题类型显示单选或复选框样式)。
QuestionOther使用 QUESTION_OTHER_VALUE 的自由文本“其他”选项。
QuestionsFooter / QuestionsSkip / QuestionsSubmit页脚操作;回答必答问题后才会启用提交。

根组件属性: Questions — items、autoAdvance、onSubmit(submission: QuestionsSubmission)、onSkip(questionId)、onDismiss()。跳过的可选问题会以 [No Preference] 提交。

属性与钩子: 仅使用内部上下文。常量:QUESTION_OTHER_VALUE、QUESTION_NO_PREFERENCE_VALUE、QUESTION_NO_PREFERENCE_LABEL。

使用说明: 当 autoAdvance 为 true 时,单选会自动前进。在多问题流程中,直到轮播的最后一张幻灯片时才显示或启用提交。

示例:

<Questions
  items={[
    {
      id: "scope",
      type: "single",
      prompt: "What should we focus on?",
      required: true,
      options: [
        { value: "perf", label: "Performance" },
        { value: "ux", label: "UX" },
      ],
    },
  ]}
  onSubmit={(submission) => console.log(submission)}
>
  <QuestionsHeader>
    <QuestionsTitle>Quick questions</QuestionsTitle>
    <QuestionsDismiss />
  </QuestionsHeader>
  <QuestionsCarousel>
    <QuestionsCarouselContent>
      {items.map((item) => (
        <QuestionsCarouselItem key={item.id}>
          <Question {...item}>
            <QuestionOptions>
              {item.options.map((option) => (
                <QuestionOption key={option.value} value={option.value}>
                  {option.label}
                </QuestionOption>
              ))}
              <QuestionOther />
            </QuestionOptions>
          </Question>
        </QuestionsCarouselItem>
      ))}
    </QuestionsCarouselContent>
  </QuestionsCarousel>
  <QuestionsFooter>
    <QuestionsSkip />
    <QuestionsSubmit />
  </QuestionsFooter>
</Questions>

AI SDK 集成

通过 @ai-sdk/react 使用 Vercel AI SDK。聊天钩子使用 transport(例如,指向你的 API 路由的 DefaultChatTransport)。使用本地状态(或你的表单库)连接文本区域,并在提交时调用 sendMessage。

import * as React from "react";
import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";
import {
  PromptInput,
  PromptInputTextarea,
  PromptInputActions,
  PromptInputActionGroup,
  PromptInputAction,
} from "@/components/nexus-ui/prompt-input";
import { Button } from "@/components/ui/button";
import { ArrowUp } from "lucide-react";

function ChatInput() {
  const [input, setInput] = React.useState("");
  const { sendMessage, status } = useChat({
    transport: new DefaultChatTransport({ api: "/api/chat" }),
  });

  const busy = status === "streaming" || status === "submitted";

  async function onSend() {
    const text = input.trim();
    if (!text || busy) return;
    await sendMessage({ text });
    setInput("");
  }

  return (
    <PromptInput>
      <PromptInputTextarea
        value={input}
        onChange={(e) => setInput(e.target.value)}
        onKeyDown={(e) => {
          if (e.key === "Enter" && !e.shiftKey) {
            e.preventDefault();
            void onSend();
          }
        }}
        disabled={busy}
      />
      <PromptInputActions>
        <PromptInputActionGroup>
          <PromptInputAction asChild>
            <Button
              type="button"
              size="icon"
              className="rounded-full"
              disabled={!input.trim() || busy}
              onClick={() => void onSend()}
            >
              <ArrowUp />
            </Button>
          </PromptInputAction>
        </PromptInputActionGroup>
      </PromptInputActions>
    </PromptInput>
  );
}

使用与 SDK 兼容的文件输入时,可通过 sendMessage({ text, files }) 在同一轮中传递附件(有关 FileList / 文件部分,请参阅当前 AI SDK 文档)。

组合原则

  1. 组合,而非配置。 优先使用小型基础组件,而非庞大的配置对象。
  2. 为提示词操作使用 asChild。 将 Button 包裹在 PromptInputAction asChild 中(适用时也可使用 SuggestionPanelClose asChild)。
  3. 对提示词操作进行分组。 在 PromptInputActions 内使用 PromptInputActionGroup,将左侧操作(附件、工具)与右侧操作(发送)分开。
  4. 掌控源代码。 组件会被复制到项目中;可直接自定义。

样式

  • 全面使用 Tailwind CSS v4 工具类。
  • 可通过任意部分的 className 覆盖样式。
  • 深色模式:dark: 变体与常见的 shadcn 风格令牌保持一致。

项目结构

components/
├── nexus-ui/
│   ├── prompt-input.tsx
│   ├── model-selector.tsx
│   ├── suggestions.tsx
│   ├── attachments.tsx
│   ├── message.tsx
│   ├── codeblock.tsx
│   ├── thread.tsx
│   ├── citation.tsx
│   ├── reasoning.tsx
│   ├── text-shimmer.tsx
│   ├── image.tsx
│   ├── feedback-bar.tsx
│   ├── toaster.tsx
│   ├── chain-of-thought.tsx
│   ├── codeblock-new.tsx
│   ├── tool.tsx
│   └── questions.tsx
├── ui/
│   ├── button.tsx
│   ├── textarea.tsx
│   ├── scroll-area.tsx
│   └── ...
└── ...

依赖项

注册表项目会按需引入以下依赖项(shadcn CLI 会安装注册表依赖项):

  • 提示词输入: @radix-ui/react-slot、shadcn textarea、scroll-area、tooltip、kbd、@/lib/utils
  • 建议: @radix-ui/react-presence、@radix-ui/react-slot、class-variance-authority、shadcn button
  • 模型选择器: radix-ui(DropdownMenu)、class-variance-authority、@hugeicons/react、@hugeicons/core-free-icons
  • 附件: @radix-ui/react-slot、class-variance-authority、@hugeicons/react、@hugeicons/core-free-icons
  • 消息: streamdown + @streamdown/* 插件、radix-ui、@radix-ui/react-slot、@hugeicons/react、@hugeicons/core-free-icons、shadcn button、avatar、tooltip、kbd
  • 线程: @radix-ui/react-slot、use-stick-to-bottom、@hugeicons/react、@hugeicons/core-free-icons
  • 引用: radix-ui、@hugeicons/react、@hugeicons/core-free-icons、shadcn carousel、hover-card
  • 推理: streamdown、@hugeicons/react、@hugeicons/core-free-icons、tw-shimmer、shadcn collapsible、用于 shimmer + collapsible 高度关键帧的注册表 CSS
  • 文本闪烁: 仅需 @/lib/utils(cn)
  • 图像: @radix-ui/react-dialog、@radix-ui/react-slot、shadcn tooltip、kbd、@/lib/utils
  • 反馈栏: @radix-ui/react-slot、shadcn tooltip、kbd、@/lib/utils
  • 通知提示: sonner、next-themes、@hugeicons/react、@hugeicons/core-free-icons、shadcn button、@/lib/utils
  • 思维链: @hugeicons/react、@hugeicons/core-free-icons、shadcn collapsible、tw-shimmer(注册表 CSS)、@/lib/use-on-change、@/lib/utils
  • 工具: @hugeicons/react、@hugeicons/core-free-icons、shiki、@react-symbols/icons、shadcn badge、collapsible、注册表 codeblock-new.tsx、lib/shiki/highlighter.ts、@/lib/utils
  • 问题: @hugeicons/react、@hugeicons/core-free-icons、shadcn carousel、button、card、checkbox、@/lib/utils

文档

评论

支持 Markdown