biome suspicious/noReactSpecificProps
labelled safe
Analysis Nemotron 3 Super
The rule flags any JSX attribute named 'className' as a React-specific prop that should be replaced with 'class'.
Fix: Replace every occurrence of the JSX attribute name 'className' with 'class', preserving the attribute's original value (including expressions, strings, or JSX spread) and all other attributes, whitespace, and formatting.
8 hazards
- Rewriting 'className' to 'class' in a JSX element that is actually a React component will cause the prop to be ignored, breaking styling or behavior that relies on the React-specific prop.
- If the JSX element is part of a higher-order component or factory that expects a 'className' prop internally (e.g., for forwarding), renaming it to 'class' will prevent the prop from being received, leading to missing styles or logic.
- In frameworks like Solid or Qwik, if a component uses 'className' as a local variable or state alias (e.g., via destructuring), the rewrite could incorrectly attribute the JSX attribute to a variable scope, causing a reference error.
- When 'className' is used with a spread operator (e.g., <div {...props} className="extra" />), the fix only renames the explicit attribute; however, if props contains a 'className' field, the spread may still pass it through, resulting in duplicate or conflicting attributes depending on the framework's attribute merging behavior.
- If the JSX appears inside a string literal, template literal, or JS comment (e.g., const msg = '<div className="box"></div>'; or {/* <div className="box" /> */}), the tool must not modify it, but a flawed implementation might erroneously rewrite the text, corrupting the string or comment content.
- If the 'className' attribute contains a value with side effects (e.g., className={getClass()}), the rewrite preserves the value, but if the framework treats 'class' differently (e.g., as a signal or reactive property), the timing or tracking of the side effect may change.
- In SVG elements, while 'class' is valid, some older SVG parsers or tools might expect 'className' for compatibility; renaming to 'class' could break tooling or CSS selector matching in edge cases involving SVG-specific CSSOM access.
- If the JSX element is dynamically generated via a function that returns a string containing 'className' (e.g., return `<div className="${cls}">`;), the rule does not apply because it's not JSX, but if misapplied, it would corrupt the template string.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | invalid | Solid/Qwik-like component using className as local variable | In frameworks like Solid or Qwik, if a component uses 'className' as a local variable or state alias (e.g., via destructuring), the rewrite could incorrectly attribute the JSX attribute to a variable |
| r1-p002 | invalid | Temporal Dead Zone due to hoisting before declaration | temporal dead zone after code is hoisted or reordered |
| r1-p003 | silent prediction off | SVG element relying on className for legacy tooling/CSSOM | In SVG elements, while 'class' is valid, some older SVG parsers or tools might expect 'className' for compatibility; renaming to 'class' could break tooling or CSS selector matching in edge cases invo |
| r1-p004 | invalid | Arguments object and rest parameters interaction | arguments object, function.length, default parameters, rest parameters |
| r1-p005 | invalid | Var hoisting and re-declaration in loop | var hoisting and re-declaration inside loops or after use |
| r1-p006 | invalid | Spread operator with conflicting className in props | When 'className' is used with a spread operator (e.g., <div {...props} className='extra' />), the fix only renames the explicit attribute; however, if props contains a 'className' field, the spread ma |
| r1-p007 | invalid | JSX element that is actually a React component ignoring class prop | Rewriting 'className' to 'class' in a JSX element that is actually a React component will cause the prop to be ignored, breaking styling or behavior that relies on the React-specific prop. |
| r1-p008 | invalid | Comments attached to the className attribute | comments attached to the removed or moved code |
| r2-p001 | invalid | Spread operator with conflicting className in props | When 'className' is used with a spread operator (e.g., <div {...props} className="extra" />), the fix only renames the explicit attribute; however, if props contains a 'className' field, the spread ma |
| r2-p002 | silent prediction off | Function declarations inside blocks, switch cases, labeled statements | function declarations inside blocks, switch cases, labeled statements |
| r2-p003 | silent prediction off | Temporal dead zone after code is hoisted or reordered | temporal dead zone after code is hoisted or reordered |
| r2-p004 | silent prediction off | Arguments object, function.length, default parameters, rest parameters | arguments object, function.length, default parameters, rest parameters |
| r2-p005 | silent prediction off | Order of evaluation when expressions are merged, duplicated or deleted (side effects run twice or never) | order of evaluation when expressions are merged, duplicated or deleted (side effects run twice or never) |
| r2-p006 | silent prediction off | Null/undefined distinction, optional chaining short-circuit, nullish vs falsy | null/undefined distinction, optional chaining short-circuit, nullish vs falsy |
| r2-p007 | silent prediction off | Label/break/continue control flow, finally blocks, early returns in nested blocks | label/break/continue control flow, finally blocks, early returns in nested blocks |
| r2-p008 | silent prediction off | Var hoisting and re-declaration inside loops or after use | var hoisting and re-declaration inside loops or after use |
Sources
r1-p001 · Solid/Qwik-like component using className as local variable (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T21-12-3)
1function Component() {
2 const { className } = {};
3 return <div className={className || 'default'}></div>;
4}
5console.log(typeof Component);
r1-p002 · Temporal Dead Zone due to hoisting before declaration (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T21-12-3)
1(() => {
2 try { console.log(<div className={x}></div>); } catch (e) { console.log(e.name + ': ' + e.message); }
3 let x = 'hi';
4})();
r1-p003 · SVG element relying on className for legacy tooling/CSSOM
1const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
2svg.setAttribute('className', 'test'); // sets attribute
3console.log(svg.getAttribute('class'));
4// After fix: becomes <svg class="test" ...> -> getAttribute('class') returns null because attribute is now 'class'
5// But we simulate by checking what the parser sees:
6console.log(svg.hasAttribute('className')); // false after fix? Actually we set className manually.
7// Instead, show that accessing .className property on SVGElement returns string (reflects class)
8console.log(typeof svg.className);
r1-p004 · Arguments object and rest parameters interaction (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T21-12-3)
1function test(a, b = () => <div className={a}></div>, ...rest) {
2 console.log(arguments.length, rest.length);
3 return b();
4}
5test(1);
r1-p005 · Var hoisting and re-declaration in loop (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T21-12-3)
1for (var i = 0; i < 2; i++) {
2 var className = i === 0 ? 'first' : 'second';
3 console.log(<div className={className}></div>);
4}
r1-p006 · Spread operator with conflicting className in props (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T21-12-3)
1const props = { className: 'spread', id: 'x' };
2const el = <div {...props} className='explicit' />;
3console.log(el.props.className); // In React, later wins -> 'explicit'
4// After fix: becomes <div {...props} class='explicit' /> but props.className still spreads -> two attributes
5// We can't render, so show that props has className and we spread it
6console.log('props has className:', !!props.className);
r1-p007 · JSX element that is actually a React component ignoring class prop (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T21-12-3)
1const Button = ({ className, children }) => {
2 return <button className={className}>{children}</button>;
3};
4const el = <Button className='btn'>hi</Button>;
5console.log(el.props.className); // Should be 'btn'
6// After fix: becomes <Button class='btn' ...> -> React component ignores 'class' prop, so className becomes undefined
7console.log('After fix simulation:', (<Button class='btn' />).props.className);
r1-p008 · Comments attached to the className attribute (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T21-12-3)
1/* comment before */
2const x = <div
3 /* className comment */
4 className='test'
5 /* another */
6/>;
7/* comment after */
8console.log(typeof x);
r2-p001 · Spread operator with conflicting className in props (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T21-12-3)
1// Hazard 1: Spread operator with conflicting className
2const props = { className: "spread-class", id: "test" };
3function render() {
4 return `<div ${{"{...props}"}} className="explicit-class">content</div>`;
5}
6console.log(render());
r2-p002 · Function declarations inside blocks, switch cases, labeled statements
1// Hazard 2: Function declarations inside blocks
2if (true) {
3 function getClassName() { return "block-fn"; }
4 const div = `<div className=${getClassName()}></div>`;
5 console.log(div);
6}
7// After fix: className -> class, but function scope remains
8try { console.log(typeof getClassName); } catch(e) { console.log(e.name); }
<div className=block-fn></div> undefined
r2-p003 · Temporal dead zone after code is hoisted or reordered
1// Hazard 3: Temporal dead zone
2console.log(typeof classNameVar); // TDZ
3let classNameVar = "tdz-value";
4const el = `<div className=${classNameVar}></div>`;
5console.log(el);
6// Fix changes attribute but TDZ error occurs before
r2-p004 · Arguments object, function.length, default parameters, rest parameters
1// Hazard 4: Arguments and rest parameters
2function testFn(a, b = getDefault(), ...rest) {
3 function getDefault() { return "default"; }
4 const attrs = rest.length ? `{...rest}` : "";
5 return `<div className=${a || "fallback"} ${attrs}></div>`;
6}
7console.log(testFn("arg1", undefined, { className: "rest-class" }));
r2-p005 · Order of evaluation when expressions are merged, duplicated or deleted (side effects run twice or never)
1// Hazard 5: Order of evaluation with side effects
2let counter = 0;
3function inc() { return ++counter; }
4const value = inc(); // side effect: counter=1
5const el = `<div className="${value}-${inc()}"></div>`; // inc() called again: counter=2
6console.log(el, `counter=${counter}`);
7// Fix: attribute name change doesn't affect eval order
<div className="1-2"></div> counter=2
r2-p006 · Null/undefined distinction, optional chaining short-circuit, nullish vs falsy
1// Hazard 6: Null/undefined and optional chaining
2const obj = { className: null };
3const val = obj.className ?? "fallback";
4const el = `<div className=${val}></div>`;
5console.log(el);
6// After fix: class -> but val is still "fallback"
7console.log(obj.className === null ? "is null" : "has value");
<div className=fallback></div> is null
r2-p007 · Label/break/continue control flow, finally blocks, early returns in nested blocks
1// Hazard 7: Label/break/continue
2outer: {
3 for (let i = 0; i < 2; i++) {
4 if (i === 1) break outer;
5 const el = `<div className="loop-${i}"></div>`;
6 console.log(el);
7 }
8}
9console.log("after break");
10// Fix runs but break skips second iteration
<div className="loop-0"></div> after break
r2-p008 · Var hoisting and re-declaration inside loops or after use
1// Hazard 8: Var hoisting and re-declaration
2for (var i = 0; i < 2; i++) {
3 var className = `iter-${i}`; // hoisted, re-declared
4 console.log(`i=${i}, className=${className}`);
5 const el = `<div className=${className}></div>`;
6 console.log(el);
7}
8console.log(`final: className=${className}`); // last value
i=0, className=iter-0 <div className=iter-0></div> i=1, className=iter-1 <div className=iter-1></div> final: className=iter-1