This ESLint warning appears when a React component lacks a displayName property, making it difficult to identify in React DevTools and error stack traces. It commonly occurs with components wrapped in React.memo(), React.forwardRef(), or higher-order components (HOCs).
The "Component definition is missing display name" error is a warning from the ESLint rule `react/display-name`. This rule enforces that all React components have a `displayName` property, which helps identify components in debugging tools like React DevTools. When you create anonymous components or wrap components with utilities like `React.memo()`, `React.forwardRef()`, or higher-order components, React cannot automatically infer a meaningful component name. Without a displayName, these components appear as "Anonymous", "ForwardRef", or "Memo" in DevTools, making debugging significantly harder. The displayName property is primarily a development convenience that helps you quickly identify which component is rendering, updating, or causing issues. While it doesn't affect production functionality, setting it improves the developer experience when using profiling tools, debugging render cycles, or analyzing component hierarchies.
If you're exporting an anonymous component, either name the function or add a displayName property:
// ❌ Before: Anonymous component
export default () => {
return <div>Hello</div>;
};
// ✅ Fix 1: Use named function
const MyComponent = () => {
return <div>Hello</div>;
};
export default MyComponent;
// ✅ Fix 2: Add displayName
const Component = () => {
return <div>Hello</div>;
};
Component.displayName = 'MyComponent';
export default Component;Named functions automatically get their displayName from the function name, making them easier to identify.
When wrapping components with React.memo(), set displayName on the memoized component:
// ❌ Before: No displayName
const MyComponent = ({ name }) => <div>Hello {name}</div>;
export default React.memo(MyComponent);
// ✅ Fix: Add displayName to memoized component
const MyComponent = ({ name }) => <div>Hello {name}</div>;
const MemoizedComponent = React.memo(MyComponent);
MemoizedComponent.displayName = 'MemoizedMyComponent';
export default MemoizedComponent;
// ✅ Alternative: More descriptive pattern
const MyComponent = ({ name }) => <div>Hello {name}</div>;
MyComponent.displayName = 'MyComponent';
const MemoizedComponent = React.memo(MyComponent);
MemoizedComponent.displayName = \`memo(${MyComponent.displayName})\`;
export default MemoizedComponent;This makes the component appear as "MemoizedMyComponent" or "memo(MyComponent)" in DevTools.
Components created with React.forwardRef() require explicit displayName:
// ❌ Before: Shows as "ForwardRef" in DevTools
const Input = React.forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
// ✅ Fix: Add displayName
const Input = React.forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
Input.displayName = 'Input';
// ✅ More descriptive pattern
const Input = React.forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
Input.displayName = 'forwardRef(Input)';
// ✅ Combining forwardRef and memo
const Input = React.forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
Input.displayName = 'Input';
const MemoInput = React.memo(Input);
MemoInput.displayName = 'memo(forwardRef(Input))';
export default MemoInput;Note: When combining memo and forwardRef, apply forwardRef first, then wrap with memo.
Higher-order components should preserve and enhance the wrapped component's displayName:
// ❌ Before: Generic HOC without displayName preservation
function withLogging(Component) {
return (props) => {
console.log('Rendering');
return <Component {...props} />;
};
}
// ✅ Fix: Preserve and enhance displayName
function withLogging(Component) {
const WithLogging = (props) => {
console.log('Rendering');
return <Component {...props} />;
};
// Get original component name
const componentName = Component.displayName || Component.name || 'Component';
// Set descriptive displayName
WithLogging.displayName = \`withLogging(${componentName})\`;
return WithLogging;
}
// Usage
const MyComponent = () => <div>Content</div>;
MyComponent.displayName = 'MyComponent';
const EnhancedComponent = withLogging(MyComponent);
// Shows as "withLogging(MyComponent)" in DevToolsThis pattern creates a hierarchy like "withLogging(withAuth(MyComponent))" for nested HOCs.
If you have a valid reason to skip displayName, disable the ESLint rule for that line:
// Disable for single line
// eslint-disable-next-line react/display-name
export default () => <div>Content</div>;
// Disable for entire file (add to top of file)
/* eslint-disable react/display-name */
// Disable for code block
/* eslint-disable react/display-name */
const Component = React.memo(() => <div>Content</div>);
/* eslint-enable react/display-name */Caution: Only disable this rule when absolutely necessary. In most cases, adding displayName is the better solution for maintainability and debugging.
To disable the rule project-wide (not recommended), update your \.eslintrc\:
{
"rules": {
"react/display-name": "off"
}
}Display name conventions and best practices:
The displayName property is purely for development and debugging purposes. It's automatically stripped in production builds when using tools like Create React App or Next.js with proper optimization.
Hierarchical naming for wrapped components:
When combining multiple wrappers (memo, forwardRef, HOCs), use hierarchical displayName to show the full component structure:
- memo(forwardRef(Button))
- withAuth(withTheme(UserProfile))
- connect(withRouter(Dashboard))
This makes it clear which wrappers are applied and in what order, which is crucial when debugging why a component re-renders or doesn't update.
TypeScript and displayName:
When using TypeScript with forwardRef, you can type the component and still set displayName:
interface InputProps {
placeholder?: string;
}
const Input = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => {
return <input ref={ref} {...props} />;
});
Input.displayName = 'Input';React DevTools and displayName:
React DevTools uses displayName as the primary identifier for components in the component tree. When profiling performance, meaningful displayName values make it much easier to identify which components are slow or re-rendering unnecessarily.
Default exports and ESLint:
Some ESLint configurations are stricter about default exports. If you're using export default with an arrow function directly, consider:
1. Using named exports instead: export const MyComponent = ...
2. Defining the component separately before exporting
3. Using named function expressions or declarations
Context and displayName:
React Context objects also benefit from displayName:
const ThemeContext = React.createContext();
ThemeContext.displayName = 'ThemeContext';This makes the context appear as "ThemeContext.Provider" and "ThemeContext.Consumer" in DevTools instead of generic "Context.Provider".
Production builds:
While displayName is stripped from production builds for size optimization, it's still valuable during development, staging, and when debugging production issues with development builds.
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