organizing-classnames
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseClassNames Usage and Conventions
ClassNames 使用规范与约定
1. Import and Component Props Pattern
1. 导入与组件属性模式
- Import from
classNamesalongside other third-party imports'classnames' - The prop must be optional:
classNameclassName?: string - Always merge the consumer's last so it can override defaults:
className
tsx
className={classNames('default-classes', className)}- 从导入
'classnames',与其他第三方包导入放在一起classNames - 属性必须是可选的:
classNameclassName?: string - 始终将使用者传入的最后 合并,以便它可以覆盖默认样式:
className
tsx
className={classNames('default-classes', className)}2. Breakpoint Order (Mobile-First)
2. 断点顺序(移动端优先)
Order classes from smallest to largest screen size — always:
base (no prefix) → xs: → s: → sm: → md: → m: → lg: → xl: → 2xl:Check the project'sfor the actual breakpoint names — they may differ.tailwind.config
类的顺序必须从最小屏幕尺寸到最大屏幕尺寸排列:
base(无前缀)→ xs: → s: → sm: → md: → m: → lg: → xl: → 2xl:请查看项目的文件确认实际的断点名称——它们可能有所不同。tailwind.config
3. Class Organization Rules
3. 类组织规则
- Group by breakpoint — each breakpoint gets its own string argument
- Order utilities logically within each group: layout → spacing → typography → colors → effects
- No trailing comma after the last argument
classNames
- 按断点分组——每个断点单独作为一个字符串参数
- 在每组内按逻辑排序工具类:布局 → 间距 → 排版 → 颜色 → 特效
- 的最后一个参数后不要加尾随逗号
classNames
4. Patterns
4. 示例模式
Basic Breakpoint Ordering
基础断点排序
tsx
className={classNames(
'base-style-1 base-style-2',
'xs:xs-style-1 xs:xs-style-2',
'sm:sm-style-1 sm:sm-style-2',
'md:md-style-1 md:md-style-2',
'lg:lg-style-1 lg:lg-style-2',
'xl:xl-style-1 xl:xl-style-2',
'2xl:2xl-style-1 2xl:2xl-style-2'
)}tsx
className={classNames(
'base-style-1 base-style-2',
'xs:xs-style-1 xs:xs-style-2',
'sm:sm-style-1 sm:sm-style-2',
'md:md-style-1 md:md-style-2',
'lg:lg-style-1 lg:lg-style-2',
'xl:xl-style-1 xl:xl-style-2',
'2xl:2xl-style-1 2xl:2xl-style-2'
)}Conditional Classes + Passed className
Prop
className条件类 + 传入的className
属性
classNametsx
type Props = {
size?: ButtonSize;
variant?: ButtonVariant;
className?: string;
};
export const Button: React.FC<Props> = ({
children,
size = ButtonSize.MEDIUM,
variant = ButtonVariant.PRIMARY,
className,
...props
}) => (
<button
className={classNames(
"block rounded-lg text-center transition",
"disabled:opacity-50",
{ "px-3 py-2 text-sm-medium": size === ButtonSize.SMALL },
{ "px-4 py-3 text-md-medium": size === ButtonSize.MEDIUM },
{
"bg-orange-500 text-white hover:bg-orange-700":
variant === ButtonVariant.PRIMARY,
},
{
"outline outline-gray-500 hover:text-orange-500":
variant === ButtonVariant.SECONDARY,
},
{ "pointer-events-none": Boolean(props?.disabled) },
className,
)}
type="button"
{...props}
>
{children}
</button>
);tsx
type Props = {
size?: ButtonSize;
variant?: ButtonVariant;
className?: string;
};
export const Button: React.FC<Props> = ({
children,
size = ButtonSize.MEDIUM,
variant = ButtonVariant.PRIMARY,
className,
...props
}) => (
<button
className={classNames(
"block rounded-lg text-center transition",
"disabled:opacity-50",
{ "px-3 py-2 text-sm-medium": size === ButtonSize.SMALL },
{ "px-4 py-3 text-md-medium": size === ButtonSize.MEDIUM },
{
"bg-orange-500 text-white hover:bg-orange-700":
variant === ButtonVariant.PRIMARY,
},
{
"outline outline-gray-500 hover:text-orange-500":
variant === ButtonVariant.SECONDARY,
},
{ "pointer-events-none": Boolean(props?.disabled) },
className,
)}
type="button"
{...props}
>
{children}
</button>
);Multiple className
Props for Sub-elements
className子元素的多个className
属性
classNameExpose separate className props for each styleable sub-element:
tsx
type Props = {
title: ReactNode;
children: ReactNode;
className?: string;
headerClassName?: string;
contentClassName?: string;
};
export const Card: React.FC<Props> = ({
title,
children,
className,
headerClassName,
contentClassName,
}) => (
<div className={classNames("rounded-lg border", className)}>
<div className={classNames("border-b p-4", headerClassName)}>{title}</div>
<div className={classNames("p-4", contentClassName)}>{children}</div>
</div>
);为每个可设置样式的子元素单独暴露className属性:
tsx
type Props = {
title: ReactNode;
children: ReactNode;
className?: string;
headerClassName?: string;
contentClassName?: string;
};
export const Card: React.FC<Props> = ({
title,
children,
className,
headerClassName,
contentClassName,
}) => (
<div className={classNames("rounded-lg border", className)}>
<div className={classNames("border-b p-4", headerClassName)}>{title}</div>
<div className={classNames("p-4", contentClassName)}>{children}</div>
</div>
);Shared Styles (Extract Reused Class Sets)
共享样式(提取复用的类集合)
Extract class sets into a variable only when they are reused by multiple elements in the same component or when the repeated class list clearly hurts readability. Do not extract one-off class sets that are used only once.
When multiple elements share the same base classes, extract to a variable:
tsx
const Buttons = () => {
const buttonClassName = classNames(
"flex w-full shrink-0 items-center justify-center transition-colors",
"lg:cursor-pointer",
);
return (
<div className="flex flex-col gap-3">
<button className={classNames(buttonClassName, "button-primary")}>
{/* Content */}
</button>
<button className={classNames(buttonClassName, "button-secondary")}>
{/* Content */}
</button>
</div>
);
};只有当类集合被同一组件中的多个元素复用,或者重复的类列表明显影响可读性时,才将其提取为变量。不要提取仅使用一次的类集合。
当多个元素共享相同的基础类时,提取到变量中:
tsx
const Buttons = () => {
const buttonClassName = classNames(
"flex w-full shrink-0 items-center justify-center transition-colors",
"lg:cursor-pointer",
);
return (
<div className="flex flex-col gap-3">
<button className={classNames(buttonClassName, "button-primary")}>
{/* Content */}
</button>
<button className={classNames(buttonClassName, "button-secondary")}>
{/* Content */}
</button>
</div>
);
};5. Quick Checklist
5. 快速检查清单
- imported from
classNames'classnames' - prop is optional
className?: string - Consumer merged at the end
className - Breakpoints ordered mobile-first (base → xs → sm → md → lg → xl → 2xl)
- Each breakpoint in its own string argument
- Utilities ordered: layout → spacing → typography → colors → effects
- No trailing comma after last argument
- Reused class sets extracted to a variable
- 从
classNames导入'classnames' - 属性为可选
className?: string - 使用者传入的在最后合并
className - 断点按移动端优先顺序排列(base → xs → sm → md → lg → xl → 2xl)
- 每个断点单独作为一个字符串参数
- 工具类排序:布局 → 间距 → 排版 → 颜色 → 特效
- 最后一个参数后无尾随逗号
- 复用的类集合已提取为变量