React JSX自定义元素className未转换为class属性如何解决
问题现象
在React项目中为Web Components自定义元素编写TS类型声明后,JSX中传入的className属性没有像内置HTML元素一样被转换为标准的class属性,而是被直接渲染为全小写的classname属性。
涉及的TS类型定义如下:
declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace JSX { interface IntrinsicElements { 'd3fc-group': DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>; 'd3fc-svg': DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>; } } }
组件中编写的JSX结构:
return ( <div ref={d3Container} className='main_layout' data-testid={'chart'}> <d3fc-group id='group' className='hellooo' style={{ display: 'flex', height: '100%', width: '100%', flexDirection: 'column' }} auto-resize> </d3fc-group> </div> );
实际渲染出的异常DOM结构:
<d3fc-group id="group" classname="hellooo" auto-resize="true" style="display: flex; height: 100%; width: 100%; flex-direction: column;"><div style="flex: 1 1 0%; display: flex; flex-direction: column;"></d3fc-group>
根本原因
TS的类型声明仅做静态类型校验,不会改变React运行时的属性处理逻辑。
React 18及更早版本对内置HTML元素和自定义元素(标签名包含连字符的元素)采用两套属性处理逻辑:
- 内置元素会自动完成属性名映射,比如将
className转为class、htmlFor转为for、对事件名和布尔属性做标准化处理 - 自定义元素默认直接将JSX传入的属性名转为小写后透传到DOM节点,不会做上述属性映射,因此
className会被直接渲染为classname
解决方案
根据使用的React版本选择对应方案即可:
React 18及更低版本
- 方案1:直接在自定义元素上使用标准HTML属性名,用
class代替className,React会正常透传该属性到DOM。同步调整TS类型避免校验报错:
// JSX中直接写class属性 <d3fc-group id='group' class='hellooo' style={{ display: 'flex', height: '100%', width: '100%', flexDirection: 'column' }} auto-resize> </d3fc-group>
// 调整TS类型定义,增加class属性支持 declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace JSX { interface IntrinsicElements { 'd3fc-group': DetailedHTMLProps<HTMLAttributes<HTMLDivElement> & { class?: string }, HTMLDivElement>; 'd3fc-svg': DetailedHTMLProps<HTMLAttributes<HTMLDivElement> & { class?: string }, HTMLDivElement>; } } }
- 方案2:如果需要统一保持
className的写法习惯,可以使用工具将自定义元素包装为标准React组件,包装后的组件会自动完成属性名映射,和内置元素行为保持一致。
React 19及更高版本
React 19重构了自定义元素的处理逻辑,默认就会和内置HTML元素一样自动完成className转class、样式对象序列化、事件名标准化等操作,直接升级React版本即可,不需要修改现有业务代码。
内容的提问来源于stack exchange,提问作者Tanrikut
相关产品推荐
相关产品推荐

