Base UI React ToggleGroup 完整 API 参考Props、类型、数据属性与源码实现解析【免费下载链接】base-uiUnstyled UI components for building accessible web apps and design systems. From the creators of Radix, Floating UI, and Material UI.项目地址: https://gitcode.com/GitHub_Trending/ba/base-ui本指南以 Base UI本仓库packages/react/src/toggle-group包的ToggleGroup组件为核心系统梳理其官方 API 参考文档types.md/react/components/toggle-group/types.md)中的全部 Props、Data Attributes、状态与事件类型并结合源码实现、官方示例与测试用例进行纵深解析。读完本文你将掌握ToggleGroup的受控/非受控用法、单选与多选切换、键盘焦点循环、与Toolbar的集成方式以及render/className/style三种渲染定制手段可直接用于构建文本格式工具栏、分段控件Segmented Control等无障碍交互组件。一、组件定位为一系列 toggle 按钮提供共享状态ToggleGroup是一个无样式unstyled的 React 组件官方定位是Provides a shared state to a series of toggle buttons——即把一组Toggle按钮来自base-ui/react/toggle的按下状态收敛到一个共享的组状态中类似按钮组或分段控件。与单选组Radio Group不同它默认允许全部取消选中且可以通过multiple属性切换为多选模式因此非常适合文本格式化工具栏粗体/斜体/下划线、文本对齐方式选择等场景。该定位可以直接在源码中得到印证ToggleGroup.tsx 的 JSDoc 注释与文档页 page.mdx/react/components/toggle-group/page.mdx#L3) 的 Subtitle 完全一致。二、快速上手导入与 Anatomy组件从base-ui/react/toggle-group单独导出官方 Anatomy 示例见 page.mdx/react/components/toggle-group/page.mdx#L13-L21)展示其作为单部件使用的方式import { ToggleGroup } from base-ui/react/toggle-group; ToggleGroup /;在实际使用中ToggleGroup需要与Toggle组合。Toggle通过value属性向组内注册自己的值而ToggleGroup用一个string[]数组即所有处于按下状态的 Toggle 的 value 集合统一管理组内按下状态。完整的组合示例为import { ToggleGroup } from base-ui/react/toggle-group; import { Toggle } from base-ui/react/toggle; ToggleGroup aria-labelText alignment defaultValue{[left]} Toggle valueleft左对齐/Toggle Toggle valuecenter居中/Toggle Toggle valueright右对齐/Toggle /ToggleGroup;需要注意的是ToggleGroup渲染的根元素默认是div并带有rolegroup见 ToggleGroup.tsx因此建议配合aria-label提供无障碍名称。测试用例 ToggleGroup.test.tsx 也验证了queryByRole(group)的语义。三、ToggleGroup Props 完整参考下表完整继承自官方 API 参考文档 types.md/react/components/toggle-group/types.md#L11-L24)PropTypeDefaultDescriptiondefaultValuestring[]-The pressed state of the toggle group represented by an array of the values of all pressed toggle buttons. This is the uncontrolled counterpart ofvalue.valuestring[]-The pressed state of the toggle group represented by an array of the values of all pressed toggle buttons. This is the controlled counterpart ofdefaultValue.onValueChange((groupValue: string[], eventDetails: ToggleGroup.ChangeEventDetails) void)-Callback fired when the pressed states of the toggle group changes.loopFocusbooleantrueWhether to loop keyboard focus back to the first item when the end of the list is reached while using the arrow keys.multiplebooleanfalseWhenfalseonly one item in the group can be pressed. If any item in the group becomes pressed, the others will become unpressed. Whentruemultiple items can be pressed.disabledbooleanfalseWhether the toggle group should ignore user interaction.orientationOrientationhorizontal-classNamestring \| ((state: ToggleGroup.State) string \| undefined)-CSS class applied to the element, or a function that returns a class based on the components state.styleReact.CSSProperties \| ((state: ToggleGroup.State) React.CSSProperties \| undefined)-Style applied to the element, or a function that returns a style object based on the components state.renderReactElement \| ((props: HTMLProps, state: ToggleGroup.State) ReactElement)-Allows you to replace the components HTML element with a different tag, or compose it with another component. Accepts aReactElementor a function that returns the element to render.3.1 受控与非受控value / defaultValue非受控传入defaultValue时组件内部自行维护按下状态用户点击后状态自动更新。官方文档将其描述为value的非受控对应物。受控传入value时按下状态完全由外部组件持有必须配合onValueChange回写否则点击后 UI 不会变化。源码层面这一对状态由useControlledHook 统一管理见 ToggleGroup.tsxconst [groupValue, setValueState] useControlled({ controlled: valueProp, default: defaultValue, name: ToggleGroup, state: value, });当defaultValue未传时源码会回退到EMPTY_ARRAYToggleGroup.tsx并借助isValueInitialized标记区分未传值与显式传空数组两种情形用于后续对Toggle缺失value时的数据一致性告警。3.2 multiple单选与多选切换multiple是ToggleGroup最核心的行为开关false默认组内同时只能有一个按钮处于按下状态某个按钮按下时其余按钮自动取消按下。点击已按下的按钮会将其取消即允许全部不选这是与 Radio Group 的关键差异。true允许多个按钮同时按下彼此独立互不影响。其内部实现逻辑在 ToggleGroup.tsx 的setGroupValue回调中多选模式下对当前groupValue数组做push按下或splice取消操作单选模式下则直接替换为[newValue]或[]。官方在 page.mdx/react/components/toggle-group/page.mdx#L25-L31) 中给出的 Multiple 示例为ToggleGroup multiple defaultValue{[bold, italic]} aria-labelText formatting options Toggle valuebold aria-labelBold / Toggle valueitalic aria-labelItalic / Toggle valueunderline aria-labelUnderline / /ToggleGroup3.3 loopFocus键盘焦点循环loopFocus默认true控制使用方向键在组内移动焦点时到达列表末尾是否回绕到第一个元素。该开关直接透传给内部基于 Composite 模式的CompositeRoot见 ToggleGroup.tsxCompositeRoot render{render} className{className} style{style} state{state} refs{[forwardedRef]} props{[defaultProps, elementProps]} loopFocus{loopFocus} enableHomeAndEndKeys orientation{orientation} /从源码结构看ToggleGroup复用了packages/react/src/internals/composite/root/CompositeRoot来提供方向键导航能力并且固定启用了enableHomeAndEndKeysHome/End 键跳转首尾。同时方向键的移动方向由orientation决定。3.4 disabled整组禁用disabled默认false为true时整个ToggleGroup忽略用户交互。值得注意的是源码中的禁用状态是合并结果ToggleGroup.tsxconst disabled (toolbarContext?.disabled ?? false) || (toolbarGroupContext?.disabled ?? false) || disabledProp;也就是说当ToggleGroup被放置于被禁用的Toolbar或ToolbarGroup中时即使自身未传disabled也会整体禁用。这一状态还会通过 Context 向下传给所有子Toggle。3.5 orientation方向感知orientation类型为Orientationhorizontal | vertical默认horizontal。它同时影响两点方向键焦点的移动方向水平组用左右键、垂直组用上下键以及根元素上的data-orientation数据属性取值。3.6 onValueChange变更回调当组内按下状态变化时触发签名如下onValueChange?: ( groupValue: Value[], eventDetails: ToggleGroup.ChangeEventDetails, ) void;第一个参数是变更后的完整按下值数组第二个参数是事件详情对象详见下文事件详情类型。从源码可以看出回调在状态写入之前被调用并且如果eventDetails.isCanceled为真组件会跳过内部状态更新ToggleGroup.tsx因此你可以在回调中通过cancel()拦截状态变更。四、渲染定制render、className 与 styleToggleGroup继承自 Base UI 的BaseUIComponentPropsdiv, ToggleGroupState见 ToggleGroup.tsx因此支持三种渲染定制方式className可以是普通字符串也可以是接收ToggleGroup.State并返回字符串的函数便于基于disabled/multiple/orientation状态做条件样式。官方 Tailwind 示例大量使用了这一点。style普通样式对象或基于状态返回样式对象的函数适合运行时动态计算样式。render允许把默认的div替换为其他标签如ul或与另一个组件组合。可传入一个 ReactElement或一个接收HTMLProps与ToggleGroup.State并返回元素的函数。三种方式会在非 Toolbar 场景下统一透传给CompositeRoot在 Toolbar 场景下则通过useRenderElement处理ToggleGroup.tsx保证任何定制都能与内部状态如data-*属性保持一致。五、Data Attributes无样式 CSS 的状态锚点由于组件无内置样式官方推荐通过数据属性编写 CSS。下表完整继承自 types.md/react/components/toggle-group/types.md#L26-L32)AttributeTypeDescriptiondata-orientationhorizontal \| verticalIndicates the orientation of the toggle group.data-disabled-Present when the toggle group is disabled.data-multiple-Present when the toggle group allows multiple buttons to be in the pressed state at the same time.这三个属性的定义可在 ToggleGroupDataAttributes.ts 中直接找到例如export const orientation data-orientation; export const disabled data-disabled; export const multiple data-multiple;官方 Tailwind 示例demos/hero/tailwind/index.tsx/react/components/toggle-group/demos/hero/tailwind/index.tsx)正是基于data-pressed等属性实现按下态样式切换data-pressed:bg-neutral-950>type ToggleGroupState { /** Whether the component should ignore user interaction. */ disabled: boolean; /** * When false only one item in the group can be pressed. If any item in * the group becomes pressed, the others will become unpressed. * When true multiple items can be pressed. * default false */ multiple: boolean; /** The orientation of the toggle group. */ orientation: Orientation; };它是className、style、render函数式用法中第二个参数的来源也是 Base UI 状态驱动的样式方案的基础。6.2 ToggleGroup.ChangeEventReasontype ToggleGroupChangeEventReason none;目前该组件所有变更事件的reason固定为none。在源码中它被定义为typeof REASONS.noneToggleGroup.tsx复用自packages/react/src/internals/reasons表明事件原因机制已就位未来若引入更多触发来源可直接扩展该联合类型。6.3 ToggleGroup.ChangeEventDetailsonValueChange的第二参数字段完整定义如下摘自 types.md/react/components/toggle-group/types.md#L62-L81)type ToggleGroupChangeEventDetails { /** The reason for the event. */ reason: none; /** The native event associated with the custom event. */ event: Event; /** Cancels Base UI from handling the event. */ cancel: () void; /** Allows the event to propagate in cases where Base UI will stop the propagation. */ allowPropagation: () void; /** Indicates whether the event has been canceled. */ isCanceled: boolean; /** Indicates whether the event is allowed to propagate. */ isPropagationAllowed: boolean; /** The element that triggered the event, if applicable. */ trigger: Element | undefined; };cancel()调用后isCanceled变为true组件会跳过内部状态更新对应 ToggleGroup.tsx 的拦截逻辑可用于实现不允许取消最后一项等业务规则。allowPropagation()在 Base UI 会主动阻止传播的场景下手动放行事件冒泡。trigger触发本次事件的 DOM 元素若存在便于定位用户点击的按钮。6.4 外部类型 OrientationOrientation是一个跨组件共享的外部类型定义于packages/react/src/internals/typestype Orientation horizontal | vertical;它同时被ToggleGroup、Toolbar、Tabs等方向敏感组件复用因此传值方式在各组件间保持一致。6.5 Canonical Types 命名映射官方文档提供了规范命名Canonical↔ 别名Alias的映射表规则为当命名空间ToggleGroup已被导入时优先用 Canonical 写法否则使用 AliasCanonicalAliasToggleGroup.StateToggleGroupStateToggleGroup.PropsToggleGroupPropsToggleGroup.ChangeEventReasonToggleGroupChangeEventReasonToggleGroup.ChangeEventDetailsToggleGroupChangeEventDetails在源码中这通过 TypeScript namespace 重新导出实现ToggleGroup.tsx两种写法类型完全等价。例如组件定义中的泛型签名ToggleGroup.PropsValue extends string便采用了 Canonical 形式。七、官方示例单选与多选实战7.1 单选文本对齐工具条官方 Hero 示例demos/hero/tailwind/index.tsx/react/components/toggle-group/demos/hero/tailwind/index.tsx)演示了默认单选模式下的文本对齐工具栏核心逻辑如下ToggleGroup aria-labelText alignment defaultValue{[left]} classNameflex gap-px p-px border border-neutral-950 dark:border-white Toggle aria-labelAlign left valueleft className...…/Toggle Toggle aria-labelAlign center valuecenter className...…/Toggle Toggle aria-labelAlign right valueright className...…/Toggle /ToggleGroup注意三个关键点aria-label为整组提供可访问名称defaultValue{[left]}设置初始选中项由于未传multiple点击任意按钮会自动取消其余按钮。7.2 多选文本格式工具栏Multiple 示例demos/multiple/tailwind/index.tsx/react/components/toggle-group/demos/multiple/tailwind/index.tsx)模拟常见的加粗/斜体/下划线格式工具栏ToggleGroup multiple defaultValue{[bold, italic]} aria-labelText formatting options classNameflex gap-px p-px border border-neutral-950 dark:border-white Toggle aria-labelBold valuebold className...…/Toggle Toggle aria-labelItalic valueitalic className...…/Toggle Toggle aria-labelUnderline valueunderline className...…/Toggle /ToggleGroupmultiple开启后bold与italic可以同时保持按下这是文本编辑器中组合样式的典型交互。仓库同时提供了 CSS Modules 版本demos/multiple/css-modules/与 Tailwind 版本供对照学习。八、源码实现解析状态、Context 与 Toolbar 集成深入阅读 ToggleGroup.tsx 的实现可以归纳出四条关键实现路径状态管理受控/非受控统一交给useControlledbase-ui/utils/useControlled更新回调经useStableCallback包装保证在依赖变化后仍能拿到最新groupValue避免闭包过期。Context 下发组件通过ToggleGroupContext.Provider下发{ value, setGroupValue, disabled, isValueInitialized }ToggleGroupContext.ts子Toggle借此读取组状态、上报自己的按下事件并在缺少value且组已初始化值时发出告警。Toolbar 集成组件会主动探测上层的ToolbarRootContext与ToolbarGroupContextToggleGroup.tsx。当处于 Toolbar 内部时焦点管理与禁用态继承自 Toolbar渲染走useRenderElement否则自行渲染CompositeRoot提供方向键与焦点循环。这解释了为什么在 Toolbar 内嵌套ToggleGroup时无需重复声明键盘导航能力。无障碍语义默认渲染div并附加rolegroup配合每个Toggle的aria-pressed状态由子组件维护整组对屏幕阅读器呈现为可切换按钮组。九、测试验证行为契约ToggleGroup.test.tsx共 605 行为上述 API 行为提供了可执行的契约证明关键断言包括无障碍角色渲染后可通过rolegroup查询到根元素#L18-L22。非受控按下状态点击valueone的按钮后该按钮aria-pressed变为true且带data-pressed另一按钮仍为false#L24-L53。defaultValue 初始选中defaultValue{[two]}时第二个按钮初始即按下点击其他按钮后互斥切换#L55-L74。Toggle 缺失 value 告警组内Toggle未传value且组已定义value/defaultValue时控制台会输出精确的错误提示#L98-L113。受控模式通过setProps重设value可同步更新 UI#L116-L120起。这些测试既验证了 Props 的行为语义也确认了aria-pressed、data-pressed等属性由Toggle侧负责输出而ToggleGroup仅负责整组状态与焦点管理——二者职责划分清晰值得在阅读源码时对照体会。十、小结ToggleGroup是 Base UI 中分组状态 键盘导航 无障碍语义三者结合的典型组件value/defaultValue/onValueChange完成状态受控闭环multiple决定单选或多选loopFocus与orientation接管键盘体验disabled支持与Toolbar联动的整组禁用className/style/render提供无样式场景下的全部渲染定制入口而data-orientation、data-disabled、data-multiple三个数据属性则让样式层能够纯粹基于状态编写。配合官方示例、源码与测试你可以在此基础上快速落地自己的分段控件或格式工具栏。【免费下载链接】base-uiUnstyled UI components for building accessible web apps and design systems. From the creators of Radix, Floating UI, and Material UI.项目地址: https://gitcode.com/GitHub_Trending/ba/base-ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考