Search keywords
mergeClassNameAndStyle className resolveProps
Latest version
Steps to reproduce
Steps:
- Open this link to live example: reproduce link
- Look at the colored TextField — it has the default class.
- Look at the transparent TextField — it doesn’t have the default class, but it should.
Current behavior
Description
When mergeClassNameAndStyle: true is configured in the theme's components, the default className from defaultProps is silently dropped if a component receives an empty string "" as className.
This commonly happens when className is computed via clsx() and all inputs are falsy — clsx(undefined, false, null) returns "", not undefined.
Steps to reproduce
const theme = createTheme({
components: {
mergeClassNameAndStyle: true,
MuiTextField: {
defaultProps: { className: 'my-default-class' }
}
}
});
// ✅ Case 1: no className → default applied
<TextField />
// → className="my-default-class"
// ✅ Case 2: non-empty className → merge works
<TextField className="custom" />
// → className="my-default-class custom"
// ❌ Case 3: empty string → default LOST
<TextField className="" />
// → className=""
// ❌ Case 4: clsx with all falsy → same as Case 3
<TextField className={clsx(maybeUndefined, maybeFalse)} />
// clsx() returns "" → default class is lost
Actual behavior
The default className is silently dropped. The component renders with className="".
Root cause
In https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/resolveProps/resolveProps.ts, the className resolution has a gap between two conditions:
// Line 1: merge path — requires props.className to be TRUTHY
if (propName === 'className' && mergeClassNameAndStyle && props.className) {
output.className = clsx(defaultProps?.className, props?.className);
}
// Line 2: fallback path — requires output[propName] to be UNDEFINED
else if (output[propName] === undefined) {
output[propName] = defaultProps[propName];
}
When props.className === "":
Merge path is skipped — "" is falsy, so && props.className !== undefined, so condition is false
Result: output.className stays as "", and the default class is never applied.
Expected behavior
When className is an empty string, the default className from theme defaultProps should be applied (same as when className is undefined).
Search keywords
mergeClassNameAndStyle className resolveProps
Latest version
Steps to reproduce
Steps:
Current behavior
Description
When
mergeClassNameAndStyle: trueis configured in the theme'scomponents, the defaultclassNamefromdefaultPropsis silently dropped if a component receives an empty string""asclassName.This commonly happens when
classNameis computed viaclsx()and all inputs are falsy —clsx(undefined, false, null)returns"", notundefined.Steps to reproduce
Actual behavior
The default className is silently dropped. The component renders with className="".
Root cause
In https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/resolveProps/resolveProps.ts, the className resolution has a gap between two conditions:
When
props.className === "":Merge path is skipped —
""is falsy, so&& props.className !== undefined, so condition isfalseResult: output.className stays as
"", and the default class is never applied.Expected behavior
When className is an empty string, the default className from theme defaultProps should be applied (same as when className is undefined).