Instruction file imported from NebulaForgeX/NFX-Identity (
.cursor/rules/frontend/components.mdc). Copyright stays with the author.
Components 编码规范
本规则说明如何组织与编写 components/ 下的可复用 UI 组件,适用于任意 React 前端项目。
文件组织
components/
├── <ComponentName>/
│ ├── index.tsx
│ ├── styles.module.css # 或 ComponentName.module.css
│ └── ...
├── index.ts # 统一导出组件与类型
└── ...
- 每个组件一个文件夹,PascalCase
- 样式使用 CSS Modules,类名 camelCase
组件结构
扩展原生 HTML 属性
export interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "size"> {
variant?: "primary" | "secondary" | "outline" | "ghost" | "danger";
size?: "small" | "medium" | "large";
fullWidth?: boolean;
leftIcon?: ReactNode;
rightIcon?: ReactNode;
loading?: boolean;
}
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ variant = "primary", size = "medium", loading = false, children, className = "", ...props }, ref) => {
const classes = [
styles.button,
styles[variant],
styles[size],
loading && styles.loading,
className,
].filter(Boolean).join(" ");
return (
<button ref={ref} className={classes} disabled={props.disabled || loading} {...props}>
{loading && <span className={styles.spinner} />}
{leftIcon && !loading && <span className={styles.leftIcon}>{leftIcon}</span>}
{children && <span className={styles.content}>{children}</span>}
{rightIcon && !loading && <span className={styles.rightIcon}>{rightIcon}</span>}
</button>
);
}
);
Button.displayName = "Button";
export default Button;
- 用
Omit排除与自定义 props 冲突的 HTML 属性(如size) - 支持
className、disabled等透传,便于页面覆盖样式 - 表单类或需 ref 的组件用
forwardRef;纯展示用memo
表单类组件(如 Input)
- 提供
label、error、helperText、leftIcon、rightIcon等可选 props - 错误状态用
error控制样式与错误文案展示 - 若项目有设计系统,尺寸、variant 与设计 token 对齐
纯展示组件
- 用
memo包裹,接收明确 props,无内部请求 - 需要文案时用
useTranslation或接收label/placeholder等 props
命名规范
- 组件文件夹与组件名:PascalCase(如
Button、SearchInput) - Props 接口:
ComponentNameProps - 样式文件:
styles.module.css或ComponentName.module.css - 类名:camelCase(
styles.inputContainer)
样式
- 条件类名用数组 +
filter(Boolean).join(" ")或模板字符串 - 支持通过
className从外部覆盖,不强制覆盖所有状态 - 若组件有多个「槽位」,用 BEM 风格或前缀避免与页面样式冲突
使用建议
- 页面内优先使用这些共享组件(如
Button、Input),而不是裸<button>、<input>,以保证交互与无障碍一致 - 图标从项目统一的图标入口按需导出(如
@/assets/icons/lucide),避免在组件内写死图标名 - 复杂组合(如带搜索的列表、带分页的表格)可再拆成「组合组件」或放在页面下的
components/,视是否复用决定是否提升到src/components
导出
- 组件 default export,类型单独 export
- 在
components/index.ts中统一导出,便于import { Button } from "@/components"