Skip to main content
interlace
Plugin: react-featuresRules

display-name

display-name rule

display-name rule

Enforce component display names for better debugging experience. This rule is part of eslint-plugin-react-features and provides LLM-optimized error messages.

Quick Summary

AspectDetails
SeverityWarning (development)
Auto-FixโŒ No (requires manual naming)
CategoryReact
ESLint MCPโœ… Optimized for ESLint MCP integration
Best ForReact projects, debugging with React DevTools

Rule Details

Why This Matters

IssueImpactSolution
๐Ÿ” React DevToolsAnonymous components show as <Unknown>Add displayName
๐Ÿ› Error Stack TracesHard to identify componentNamed components
๐Ÿ“Š Performance ToolsCan't identify slow componentsClear naming
๐Ÿงช TestingSelectors may failConsistent names

Configuration

This rule has no configuration options.

Examples

โŒ Incorrect

// Anonymous arrow function
const MyComponent = () => {
  return <div>Hello</div>;
};

// Anonymous function expression
const AnotherComponent = function() {
  return <div>World</div>;
};

// Class without displayName
class UserCard extends React.Component {
  render() {
    return <div>{this.props.name}</div>;
  }
}

// HOC without displayName
const withAuth = (WrappedComponent) => {
  return (props) => <WrappedComponent {...props} />;  // โŒ No name
};

โœ… Correct

MyComponent

Configuration Examples

Basic Usage

{
  rules: {
    'react-features/display-name': 'warn'
  }
}

Strict Mode

{
  rules: {
    'react-features/display-name': 'error'
  }
}

Common Patterns

Higher-Order Components

function withLogger(WrappedComponent) {
  const WithLogger = (props) => {
    console.log('Rendering:', WrappedComponent.displayName);
    return <WrappedComponent {...props} />;
  };
  
  // Set displayName for debugging
  WithLogger.displayName = `withLogger(${
    WrappedComponent.displayName || 
    WrappedComponent.name || 
    'Component'
  })`;
  
  return WithLogger;
}

React.forwardRef

const TextInput = React.forwardRef<HTMLInputElement, InputProps>(
  (props, ref) => <input ref={ref} {...props} />
);
TextInput.displayName = 'TextInput';

React.memo

const ExpensiveList = React.memo(({ items }) => {
  return items.map(item => <Item key={item.id} {...item} />);
});
ExpensiveList.displayName = 'ExpensiveList';

Context Components

const ThemeContext = React.createContext(defaultTheme);

const ThemeProvider = ({ children, theme }) => {
  return (
    <ThemeContext.Provider value={theme}>
      {children}
    </ThemeContext.Provider>
  );
};
ThemeProvider.displayName = 'ThemeProvider';

When Not To Use

ScenarioRecommendation
๐Ÿš€ Production buildsdisplayName is stripped in prod anyway
๐Ÿงช Test utilitiesMay not need debugging names
๐Ÿ“ฆ Tiny componentsNamed exports may be sufficient

Comparison with Alternatives

Featuredisplay-nameeslint-plugin-reactReact DevTools
Class componentsโœ… Yesโœ… Yesโœ… Shows name
Function componentsโœ… Yesโœ… Yesโš ๏ธ May be Anonymous
HOCsโœ… Enforces namingโš ๏ธ LimitedโŒ Shows wrapper
LLM-Optimizedโœ… YesโŒ NoโŒ No
ESLint MCPโœ… OptimizedโŒ NoโŒ No

Further Reading

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Dynamic Variable References

Why: Static analysis cannot trace values stored in variables or passed through function parameters.

// โŒ NOT DETECTED - Prop from variable
const propValue = computedValue;
<Component prop={propValue} /> // Computation not analyzed

Mitigation: Implement runtime validation and review code manually. Consider using TypeScript branded types for validated inputs.

Imported Values

Why: When values come from imports, the rule cannot analyze their origin or construction.

// โŒ NOT DETECTED - Value from import
import { getValue } from './helpers';
processValue(getValue()); // Cross-file not tracked

Mitigation: Ensure imported values follow the same constraints. Use TypeScript for type safety.

Not a finding

React reads a component's display name off Function.name or Class.name. A component with a name is already named โ€” there is nothing to fix and nothing to report.

CodeWhy it is silent
function Profile() { ... }Named by the function.
const Profile = () => ...Named by the binding.
class Profile extends Component { ... }Named by the class; static displayName is optional.
const Row = memo(() => <div />)The binding names the component through the wrapper.

If it fires, React genuinely cannot name it: an anonymous export default, an anonymous class component, or memo/forwardRef with no binding to take a name from. Those render as Anonymous in DevTools and in every component stack trace.

Did this rule catch something? Star the repo to get new CWE coverage as we ship it โ€” or follow the AI-code-security benchmarks behind these rules.