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.

Use this rule

npm install -D oxlint-plugin-react-features
.oxlintrc.json
{  "jsPlugins": ["oxlint-plugin-react-features"],  "rules": {    "react-features/display-name": "error"  }}
vite.config.ts
import { defineConfig } from 'vite-plus';export default defineConfig({  lint: {    jsPlugins: ['oxlint-plugin-react-features'],    rules: {      'react-features/display-name': 'error',    },  },});

oxlint-plugin-react-features re-exports eslint-plugin-react-features/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.

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.