发布时间:2026/9/5 20:06:15
shadcn/ui 的 Base 与 Radix 两套组件 API 差异实战:render、items 与 defaultValue 的正确写法 shadcn/ui 的 Base 与 Radix 两套组件 API 差异实战render、items 与 defaultValue 的正确写法【免费下载链接】uiA set of beautifully-designed, accessible components and a code distribution platform. Works with your favorite frameworks. Open Source. Open Code.项目地址: https://gitcode.com/GitHub_Trending/ui/uishadcn/ui 仓库在组件注册表中同时维护了基于 Base UIbase与基于 Radix UIradix的两套并行组件实现两者的组合方式asChildvsrender、Select 的数据驱动模型、以及defaultValue的值类型均存在系统性差异。本文以仓库中的 base-vs-radix 规则文档 为主体完整覆盖其全部差异点与正误代码对照并结合 CLI 源码与注册表目录结构说明如何确认当前项目属于哪一套 API从而避免在迁移或跨项目复用组件代码时写出编译不通过或行为不符预期的 JSX。先确认你的项目用的是哪一套npx shadcn info的base字段规则文档的开篇要求先运行npx shadcnlatest info查看输出中的base字段再决定按哪一套 API 编写代码。该字段由 CLI 的 info 命令 生成// packages/shadcn/src/commands/info.ts const config await getConfig(cwd) const base getBase(config?.style)而base的取值逻辑实现在 getBase 函数// packages/shadcn/src/utils/get-config.ts export function getBase(style: string | undefined): PresetBase { // An undefined style means no existing config, so default to base. // Any defined style, including empty and unprefixed legacy values // (new-york, new-york-v4, default), stays radix. if (style undefined) { return base } return parsePresetStyle(style).base ?? radix }从源码结构看可以得出两条实用结论没有components.json配置全新项目时默认归入base任何已定义的 style包括new-york、new-york-v4等遗留值都会停留在radix。也就是说base/radix不是两个可自由混搭的组件库而是同一项目必须整体选定的两套 API。仓库中这两套实现分别位于 apps/v4/registry/bases/base 与 apps/v4/registry/bases/radix 两个并行目录注册表 README 明确要求对任何共享表面同样的预览块、同样的示例意图变更应同时应用到两套变体只调整必须不同的部分——导入路径.../base/ui/...与.../radix/ui/...和原语 API。这正解释了为什么本文列出的每一条差异都必须“成对记忆”同名的DialogTrigger、Select、Accordion在两个目录下的 props 签名并不相同。组合方式radix 用asChildbase 用render两套 API 最基础、也最普遍的区别在于“替换默认元素”的组合机制Radix 使用asChild把默认元素替换为子元素Base 使用renderprop 声明渲染成什么元素。无论哪一套都不要用多余的包裹元素套住 trigger。错误写法两种体系都错DialogTrigger div ButtonOpen/Button /div /DialogTrigger正确写法radixDialogTrigger asChild ButtonOpen/Button /DialogTrigger正确写法baseDialogTrigger render{Button /}Open/DialogTrigger注意两者子内容的语义差异radix 的asChild是“用唯一子元素替换自身”子元素即触发按钮base 的render是“把自身渲染为指定元素”触发文案作为 children 传入。这个差异在 base 注册表的组件源码中随处可见例如 alert-dialog.tsxAlertDialogPrimitive.Cancel >Button render{a href/docs /}Read the docs/Button正确baseButton render{a href/docs /} nativeButton{false} Read the docs /Button等价写法radixButton asChild a href/docsRead the docs/a /Button同样的规则适用于render不是Button的 trigger 组件// base. PopoverTrigger render{InputGroupAddon /} nativeButton{false} Pick date /PopoverTrigger判断口诀只要渲染目标是a、span这类非button元素base 体系就补一个nativeButton{false}radix 体系没有这个 prop用asChild即可。Select 差异items prop、placeholder 与定位Select 是两套 API 差异最大的组件之一共有四个差异点。items propbase 必须在根节点声明base 体系要求根Select携带items数组数据驱动radix 体系只使用内联 JSX。错误base——缺少itemsSelect SelectTriggerSelectValue placeholderSelect a fruit //SelectTrigger /Select正确baseconst items [ { label: Select a fruit, value: null }, { label: Apple, value: apple }, { label: Banana, value: banana }, ] Select items{items} SelectTrigger SelectValue / /SelectTrigger SelectContent SelectGroup {items.map((item) ( SelectItem key{item.value} value{item.value}{item.label}/SelectItem ))} /SelectGroup /SelectContent /Select正确radix——纯内联 JSXSelect SelectTrigger SelectValue placeholderSelect a fruit / /SelectTrigger SelectContent SelectGroup SelectItem valueappleApple/SelectItem SelectItem valuebananaBanana/SelectItem /SelectGroup /SelectContent /Selectplaceholderbase 用value: null项radix 用placeholderpropbase在items数组里放一个{ label: ..., value: null }项SelectValue /不再需要placeholderradixSelectValue placeholderSelect a fruit /。迁移时的典型错误就是把 radix 的placeholder...原样带到 base 版本结果占位文案不显示——base 的占位是数据不是 prop。内容定位alignItemWithTriggervsposition两套体系对浮层定位的 prop 命名不同// base. SelectContent alignItemWithTrigger{false} sidebottom // radix. SelectContent positionpopperbasealignItemWithTrigger{false}表示列表不强制与选中项对齐radixpositionpopper表示用 popper 定位相对触发器否则为item-aligned。Select 多选与对象值base 独有base 体系支持multiple、SelectValue的渲染函数 children以及配合itemToStringValue的对象值radix 体系的Select只支持单选且值只能是字符串。这两组能力在跨体系迁移时没有对等物需要改用Combobox等其他组件替代radix 侧多选通常由 Combobox 承担。base——多选Select items{items} multiple defaultValue{[]} SelectTrigger SelectValue {(value: string[]) value.length 0 ? Select fruits : ${value.length} selected} /SelectValue /SelectTrigger ... /Selectbase——对象值Select defaultValue{plans[0]} itemToStringValue{(plan) plan.name} SelectTrigger SelectValue{(value) value.name}/SelectValue /SelectTrigger ... /Select两个要点itemToStringValue负责把对象值序列化为字符串用于内部状态与无障碍播报SelectValue的 children 作为渲染函数接收当前值可渲染对象上的任意字段。radix 体系两者皆无遇到对象值场景不要硬套Select。ToggleGroupradix 用typebase 用multiple布尔值单选/多选的开关在两套体系中表达方式不同且base 的defaultValue永远是数组radix 单选时是字符串。错误base——误用 radix 的typepropToggleGroup typesingle defaultValuedaily ToggleGroupItem valuedailyDaily/ToggleGroupItem /ToggleGroup正确base// Single (no prop needed), defaultValue is always an array. ToggleGroup defaultValue{[daily]} spacing{2} ToggleGroupItem valuedailyDaily/ToggleGroupItem ToggleGroupItem valueweeklyWeekly/ToggleGroupItem /ToggleGroup // Multi-selection. ToggleGroup multiple ToggleGroupItem valueboldBold/ToggleGroupItem ToggleGroupItem valueitalicItalic/ToggleGroupItem /ToggleGroup正确radix// Single, defaultValue is a string. ToggleGroup typesingle defaultValuedaily spacing{2} ToggleGroupItem valuedailyDaily/ToggleGroupItem ToggleGroupItem valueweeklyWeekly/ToggleGroupItem /ToggleGroup // Multi-selection. ToggleGroup typemultiple ToggleGroupItem valueboldBold/ToggleGroupItem ToggleGroupItem valueitalicItalic/ToggleGroupItem /ToggleGroup对照总结能力baseradix单选默认无需 proptypesingle多选multipletypemultipledefaultValue类型恒为数组[daily]单选为字符串daily受控单选值的差异最能体现“base 一切皆数组”的设计// base — wrap/unwrap arrays. const [value, setValue] React.useState(normal) ToggleGroup value{[value]} onValueChange{(v) setValue(v[0])} // radix — plain string. const [value, setValue] React.useState(normal) ToggleGroup typesingle value{value} onValueChange{setValue}base 侧需要在边界处做“数组包装 / 拆包”value{[value]}进、v[0]出radix 侧直接透传字符串。迁移受控组件时漏掉这层包装是典型故障点。Sliderbase 单滑块可传标量radix 恒为数组Base 对单滑块接受普通数字Radix 一律要求数组因为 Radix Slider 原生就是多滑块模型。错误base——给单滑块传数组Slider defaultValue{[50]} max{100} step{1} /正确baseSlider defaultValue{50} max{100} step{1} /正确radixSlider defaultValue{[50]} max{100} step{1} /范围滑块range slider两边都用数组。受控的onValueChange在 base 下可能需要类型断言// base. const [value, setValue] React.useState([0.3, 0.7]) Slider value{value} onValueChange{(v) setValue(v as number[])} / // radix. const [value, setValue] React.useState([0.3, 0.7]) Slider value{value} onValueChange{setValue} /base 中onValueChange的回调参数类型同时覆盖标量与数组两种形态因此范围滑块场景需要v as number[]断言后写入 state。Accordiontype/collapsibleradixvsmultiplebaseRadix 要求显式typesingle或typemultiple并支持collapsible允许收起已展开项defaultValue是字符串。Base 没有typeprop用multiple布尔值控制多选defaultValue永远是数组。错误base——照搬 radix 的写法Accordion typesingle collapsible defaultValueitem-1 AccordionItem valueitem-1.../AccordionItem /Accordion正确baseAccordion defaultValue{[item-1]} AccordionItem valueitem-1.../AccordionItem /Accordion // Multi-select. Accordion multiple defaultValue{[item-1, item-2]} AccordionItem valueitem-1.../AccordionItem AccordionItem valueitem-2.../AccordionItem /Accordion正确radixAccordion typesingle collapsible defaultValueitem-1 AccordionItem valueitem-1.../AccordionItem /Accordion迁移与双目录维护仓库给出的工程化支撑上述逐组件差异之所以值得沉淀成规则文档是因为仓库中存在大量从 radix 到 base 的存量迁移与并行维护工作。两点工程化事实可以作为佐证并行注册表结构apps/v4/registry/bases 目录下base/与radix/两套组件一一对应如 base/ui/accordion.tsx 与 radix 侧同名文件bases README 要求共享表面的变更同时落到两边仅调整导入路径与原语 API。迁移技能与映射表仓库自带 migrate-radix-to-base 技能并按组件类别拆分了 menus.md、overlays.md、form-controls.md 等映射文档与 shadcn 技能规则目录 互为配套CLI 侧也提供 migrate 命令 供项目执行迁移。对开发者而言日常只需记住规则文档的判定路径先看info输出的base字段确定体系再按对应一侧的写法实现组件跨项目复制粘贴代码时把asChild/render、type/multiple、字符串 / 数组defaultValue、placeholder/value: null这四组差异当成必查清单。速查表场景baseBase UIradixRadix UI元素替换render{Button /}asChild 子元素渲染为非 button 元素追加nativeButton{false}无需额外 propSelect 选项根节点items数组内联SelectItemJSXSelect 占位{ label, value: null }项SelectValue placeholder... /Select 定位alignItemWithTriggerpositionpopperSelect 多选 / 对象值multiple、itemToStringValue、渲染函数 children不支持仅单选字符串值ToggleGroup 多选multipletypemultipleToggleGroup 单选默认typesingleToggleGroupdefaultValue恒为数组单选为字符串Slider 单滑块值标量50数组[50]Accordion 类型无typemultiple布尔typesingle \| multiple支持collapsibleAccordiondefaultValue恒为数组单选为字符串参考依据规则文档 base-vs-radix.md、info 命令实现、getBase 取值逻辑、注册表并行结构说明 以及 base 侧组件源码如 alert-dialog.tsx 的render用法。【免费下载链接】uiA set of beautifully-designed, accessible components and a code distribution platform. Works with your favorite frameworks. Open Source. Open Code.项目地址: https://gitcode.com/GitHub_Trending/ui/ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

2026/9/5 20:01:15

AI辅助开发A股量化工具:回测校验与实战防坑指南

前两天有人私信我,说想用AI直接给推几只明天能涨的股票。我回了一句:这个方向从起跑线就歪了。大模型并不适合用来猜行情,它真正擅长的是帮我把“量化工具”这种工程强度很高的东西快速落地。我自己最近就在用AI开发一个A股量化研究工具&…

2026/9/5 20:51:18

AI编程实战:打造带RAG问答的个人博客知识库

1. 项目全景:我在搭一个什么样的“博客知识库”1.1 一句话讲清项目在做的事我给自己定了这样一个目标:用AI编程把一个博客站点从零搭起来,并且让博客自带一个能问答的RAG知识库。这个知识库不是花架子,而是要真的能回答我积累的文…

2026/9/5 20:51:18

图RAG烹饪问答系统:Neo4j+Milvus双路召回实践

你有没有遇到过这种情况:想做一道菜,网上搜了一堆菜谱,但每个菜谱都默认你有某种食材或调料,而你想问的是“能不能不放花生”“有没有替代猪肉的办法”“宫保鸡丁和鱼香肉丝都用什么技法”这类需要把菜谱拆开、跨菜谱比较的问题。…

2026/9/5 20:51:18

WeChatMsg:4 步免费导出微信聊天记录,永久保存

WeChatMsg:4 步免费导出微信聊天记录,永久保存 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/W…

2026/9/5 2:46:54

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/5 2:46:52

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/5 2:44:34

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/5 0:04:47

流式背压机制:避免前端渲染卡死与内存暴涨的滑动窗口限流

流式背压机制:避免前端渲染卡死与内存暴涨的滑动窗口限流在大模型流式输出(Streaming)与智能体实时推流的架构中,生产环境中经常出现一种“上下游生产消费速率严重失衡”的极端情况: 生产端极速产出:大模型…

2026/9/5 2:45:13

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/5 2:30:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/5 2:46:50

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…