This ESLint warning appears when React components, especially those wrapped in forwardRef, memo, or higher-order components (HOCs), lack an explicit displayName property. While not breaking your app, missing displayNames make debugging harder in React DevTools and error stack traces.
The `displayName` property is a string used by React to identify components in debugging messages and React DevTools. When you create components using `React.forwardRef()`, `React.memo()`, or higher-order component patterns, React cannot automatically infer a meaningful name from the function declaration. This ESLint warning (from the `react/display-name` rule in eslint-plugin-react) alerts you when components are missing this property. The warning commonly appears with: - Components wrapped in `React.forwardRef()` - Components wrapped in `React.memo()` - Anonymous function components returned from HOCs - Context providers and consumers without explicit names While your application will run fine without displayName, debugging becomes significantly harder when React DevTools shows "Anonymous" or "ForwardRef" instead of meaningful component names.
If you're using React.forwardRef(), assign displayName to the returned component:
import React from 'react';
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
(props, ref) => {
return <button ref={ref} {...props} />;
}
);
// Add this line
Button.displayName = 'Button';
export default Button;This makes the component show as "Button" in React DevTools instead of "ForwardRef".
For memoized components, set displayName after wrapping:
import React from 'react';
const ExpensiveComponent: React.FC<Props> = ({ data }) => {
// Component logic
return <div>{data}</div>;
};
const MemoizedComponent = React.memo(ExpensiveComponent);
MemoizedComponent.displayName = 'ExpensiveComponent';
export default MemoizedComponent;Alternative: Set displayName on the original component before wrapping:
ExpensiveComponent.displayName = 'ExpensiveComponent';
const MemoizedComponent = React.memo(ExpensiveComponent);When combining memo and forwardRef, use descriptive names showing the wrapper hierarchy:
import React from 'react';
const Input = React.forwardRef<HTMLInputElement, InputProps>(
(props, ref) => {
return <input ref={ref} {...props} />;
}
);
// Apply forwardRef first, then memo
const MemoizedInput = React.memo(Input);
// Use hierarchical naming
MemoizedInput.displayName = 'memo(Input)';
export default MemoizedInput;This helps you understand the component structure in DevTools.
For HOCs, include both the HOC name and wrapped component name:
function withSubscription<P extends object>(
WrappedComponent: React.ComponentType<P>
) {
const ComponentWithSubscription: React.FC<P> = (props) => {
// HOC logic
return <WrappedComponent {...props} />;
};
// Get wrapped component name
const wrappedName =
WrappedComponent.displayName ||
WrappedComponent.name ||
'Component';
// Set hierarchical displayName
ComponentWithSubscription.displayName =
`withSubscription(${wrappedName})`;
return ComponentWithSubscription;
}
// Usage
const CommentList: React.FC = () => <div>Comments</div>;
CommentList.displayName = 'CommentList';
export default withSubscription(CommentList);
// Shows as "withSubscription(CommentList)" in DevToolsConvert arrow functions to named function declarations to automatically provide names:
// Before: Anonymous arrow function
export default React.forwardRef((props, ref) => {
return <button ref={ref} {...props} />;
});
// After: Named function declaration
export default React.forwardRef(function Button(props, ref) {
return <button ref={ref} {...props} />;
});React can infer the displayName from the function name, though explicitly setting it is still best practice.
If you prefer not to set displayName, configure the rule in .eslintrc.js:
module.exports = {
rules: {
// Disable entirely (not recommended)
'react/display-name': 'off',
// Or configure with options
'react/display-name': [
'warn', // Change from 'error' to 'warn'
{
ignoreTranspilerName: false,
checkContextObjects: false, // Don't check Context objects
},
],
},
};Suppress for specific lines:
// eslint-disable-next-line react/display-name
export default React.forwardRef((props, ref) => {
return <button ref={ref} {...props} />;
});Modern React and displayName inference:
React 18+ has improved automatic displayName inference in some cases, but explicit displayName is still needed for forwardRef, memo, and HOCs due to how they wrap components.
TypeScript considerations:
When using TypeScript with generics in HOCs or forwardRef, ensure displayName is set after all type parameters are resolved:
const GenericComponent = <T extends unknown>(props: Props<T>) => {
return <div>{/* ... */}</div>;
};
GenericComponent.displayName = 'GenericComponent';React DevTools display:
The React DevTools extension uses displayName to show component hierarchies. Without it, your component tree becomes difficult to navigate, especially in large applications with many wrapped components.
Performance and production builds:
Setting displayName has negligible runtime cost but significant debugging value. Even in production builds, displayName helps identify components in error boundaries and crash reports.
ESLint plugin versions:
The react/display-name rule behavior has evolved across eslint-plugin-react versions. Check your version's documentation for specific configuration options: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/display-name.md
Context components:
React Context Providers and Consumers also benefit from displayName:
const UserContext = React.createContext(defaultValue);
UserContext.displayName = 'UserContext';
// DevTools shows: <UserContext.Provider>Common ESLint configuration patterns:
Many teams set this rule to "warn" instead of "error" during development but enforce it in CI:
- Development: Allows quick iteration without breaking hot reload
- CI/Production: Enforces displayName for maintainability
Third-party libraries:
Popular libraries like react-hook-form, Material-UI, and Ant Design extensively use displayName in their wrapped components. Following this pattern ensures consistency with the ecosystem.
React.FC expects children prop to be defined
React.FC no longer includes implicit children prop
Warning: You provided a `selected` prop to a form field without an `onChange` handler
You provided a 'selected' prop without an onChange handler
Failed to load source map from suspense chunk
How to fix "Failed to load source map from suspense chunk" in React
Prop spreading could cause security issues
Prop spreading could cause security issues
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency