You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Storybook中使用Radix UI复合组件并控制其Props?

解决Radix UI封装Checkbox在Storybook中无法控制原生Props的问题

核心原因

封装组件时未透传Radix原生Root和Indicator的Props,或Storybook未正确识别组件的类型定义。

具体解决方案

1. 确保封装组件透传所有原生Props

封装时必须将Radix CheckboxRoot的所有原生Props通过...props透传,同时如果需要控制Indicator的Props,也要单独透传其属性。

示例代码:

import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
import { cn } from '@/lib/utils'; // 自定义样式拼接工具

// 继承Radix原生CheckboxRoot的Props,同时添加自定义属性
type CheckboxProps = CheckboxPrimitive.CheckboxProps & {
  indicatorClassName?: string;
  // 可选:直接透传Indicator的所有Props
  indicatorProps?: React.ComponentProps<typeof CheckboxPrimitive.Indicator>;
};

const Checkbox = ({ className, indicatorClassName, indicatorProps, ...props }: CheckboxProps) => {
  return (
    <CheckboxPrimitive.Root
      className={cn('flex h-4 w-4 items-center justify-center rounded border border-slate-300', className)}
      {...props} // 透传Root的所有原生Props
    >
      <CheckboxPrimitive.Indicator
        className={cn('text-white', indicatorClassName)}
        {...indicatorProps} // 透传Indicator的Props
      >
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="h-3 w-3">
          <path fillRule="evenodd" d="M19.916 4.626a.75.75 0 0 1 .208 1.04l-9 13.5a.75.75 0 0 1-1.154.114l-6-6a.75.75 0 0 1 1.06-1.06l5.353 5.353 8.493-12.739a.75.75 0 0 1 1.04-.208Z" clipRule="evenodd" />
        </svg>
      </CheckboxPrimitive.Indicator>
    </CheckboxPrimitive.Root>
  );
};

export default Checkbox;

2. 配置Storybook识别组件类型

确保Storybook能正确解析组件的TypeScript类型,自动生成Controls面板:

  • 安装必要插件:确保已安装@storybook/addon-controls和@storybook/addon-docs,并在.storybook/main.ts中注册:
import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  addons: [
    '@storybook/addon-controls',
    '@storybook/addon-docs'
  ],
  // 其他配置项
};
export default config;
  • 在stories文件中显式关联组件类型:
import Checkbox from './Checkbox';
import type { Meta, StoryObj } from '@storybook/react';

const meta: Meta<typeof Checkbox> = {
  component: Checkbox,
  title: 'Components/Checkbox',
  // 可选:自动推断不全时,手动补充argTypes
  argTypes: {
    checked: { control: 'boolean', description: '控制选中状态' },
    disabled: { control: 'boolean', description: '禁用复选框' },
    defaultChecked: { control: 'boolean', description: '默认选中状态' },
    name: { control: 'text', description: '表单name属性' },
    // 若透传了indicatorProps,可手动添加对应控制项
    indicatorProps: { control: 'object', description: 'Indicator组件的原生属性' }
  }
};

export default meta;
type Story = StoryObj<typeof Checkbox>;

export const Default: Story = {
  args: {
    checked: false,
    disabled: false
  }
};

3. 可选:将IndicatorProps展开到组件顶层

如果希望在Storybook面板中直接控制Indicator的单个属性(而非嵌套的indicatorProps对象),可以拆分Root和Indicator的Props:

import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
import { cn } from '@/lib/utils';

// 合并Root和Indicator的Props,排除重复的children属性
type CheckboxProps = CheckboxPrimitive.CheckboxProps &
  Omit<React.ComponentProps<typeof CheckboxPrimitive.Indicator>, 'children'> & {
    className?: string;
    indicatorClassName?: string;
  };

const Checkbox = ({ className, indicatorClassName, ...props }: CheckboxProps) => {
  // 分离Root和Indicator的Props
  const rootPropKeys = Object.keys(CheckboxPrimitive.CheckboxProps);
  const rootProps = Object.fromEntries(
    Object.entries(props).filter(([key]) => rootPropKeys.includes(key))
  ) as CheckboxPrimitive.CheckboxProps;
  const indicatorProps = Object.fromEntries(
    Object.entries(props).filter(([key]) => !rootPropKeys.includes(key))
  ) as Omit<React.ComponentProps<typeof CheckboxPrimitive.Indicator>, 'children'>;

  return (
    <CheckboxPrimitive.Root
      className={cn('flex h-4 w-4 items-center justify-center rounded border border-slate-300', className)}
      {...rootProps}
    >
      <CheckboxPrimitive.Indicator
        className={cn('text-white', indicatorClassName)}
        {...indicatorProps}
      >
        {/* 指示器内容 */}
      </CheckboxPrimitive.Indicator>
    </CheckboxPrimitive.Root>
  );
};

这样Storybook会自动将Indicator的原生Props(如aria-label、style等)显示在Controls面板的顶层,方便直接控制。

内容的提问来源于stack exchange,提问作者darkhorse

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:05:31