Skip to main content
interlace
Plugin: react-featuresRules

jsx-key

jsx-key rule

Keywords: React, JSX, key prop, reconciliation, lists, map, iteration, ESLint rule, performance, LLM-optimized

Detect missing or problematic React keys that could break reconciliation. This rule is part of eslint-plugin-react-features and provides LLM-optimized error messages with suggestions.

Quick Summary

AspectDetails
SeverityError (correctness)
Auto-Fix๐Ÿ’ก Suggests fixes
CategoryReact
ESLint MCPโœ… Optimized for ESLint MCP integration
Best ForAll React/JSX projects

Rule Details

Why This Matters

IssueImpactSolution
๐Ÿ”„ ReconciliationReact can't track elementsAdd unique keys
โšก PerformanceUnnecessary re-rendersStable keys
๐Ÿ› State BugsWrong component gets stateUse item IDs, not indexes
๐ŸŽจ Animation IssuesElements animate incorrectlyConsistent key identity

Configuration

OptionTypeDefaultDescription
warnUnstableKeysbooleantrueWarn about potentially unstable keys

Examples

โŒ Incorrect

// Missing key
function UserList({ users }) {
  return (
    <ul>
      {users.map(user => (
        <li>{user.name}</li>  // โŒ Missing key
      ))}
    </ul>
  );
}

// Using index as key (unstable)
function ItemList({ items }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item.name}</li>  // โš ๏ธ Unstable key
      ))}
    </ul>
  );
}

โœ… Correct

// Using unique ID as key
function UserList({ users }) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>  // โœ… Stable unique key
      ))}
    </ul>
  );
}

// Using compound key when no ID available
function ItemList({ items }) {
  return (
    <ul>
      {items.map(item => (
        <li key={`${item.category}-${item.name}`}>
          {item.name}
        </li>  // โœ… Unique compound key
      ))}
    </ul>
  );
}

Configuration Examples

Basic Usage

{
  rules: {
    'react-features/jsx-key': 'error'
  }
}

Disable Unstable Key Warnings

{
  rules: {
    'react-features/jsx-key': ['error', {
      warnUnstableKeys: false
    }]
  }
}

Key Best Practices

Choosing Keys

SourceQualityExample
Database IDโœ… Bestkey={user.id}
Unique fieldโœ… Goodkey={item.slug}
Compound uniqueโœ… Goodkey={cat + '-' + name}
UUID/nanoidโš ๏ธ OKkey={generateId()}
Array indexโŒ Avoidkey={index}
Random numberโŒ Neverkey={Math.random()}

When Index Keys Are Acceptable

// โœ… Static list that never reorders/filters
const WEEKDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'];
<ul>
  {WEEKDAYS.map((day, i) => <li key={i}>{day}</li>)}
</ul>

// โŒ Dynamic list - DON'T use index
{users.map((user, i) => <UserCard key={i} user={user} />)}  // Bad!
{users.map(user => <UserCard key={user.id} user={user} />)} // Good!

Common Patterns

Fragment Keys

// When using fragments in lists, key goes on Fragment
function DataList({ data }) {
  return (
    <>
      {data.map(item => (
        <React.Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.definition}</dd>
        </React.Fragment>
      ))}
    </>
  );
}

Nested Lists

function NestedList({ categories }) {
  return categories.map(category => (
    <div key={category.id}>
      <h2>{category.name}</h2>
      <ul>
        {category.items.map(item => (
          <li key={item.id}>{item.name}</li>  // Separate key namespace
        ))}
      </ul>
    </div>
  ));
}

When Not To Use

ScenarioRecommendation
๐Ÿงช Testing/PrototypesConsider allowing index keys temporarily
๐Ÿ“Š Static contentIndex keys may be acceptable
๐Ÿ”„ No reorderingIndex keys work for append-only lists

Comparison with Alternatives

Featurejsx-keyeslint-plugin-reactjsx-ally
Missing keyโœ… Yesโœ… YesโŒ No
Unstable keysโœ… Configurableโš ๏ธ LimitedโŒ No
LLM-Optimizedโœ… YesโŒ NoโŒ No
ESLint MCPโœ… OptimizedโŒ NoโŒ No
Suggestionsโœ… Yesโš ๏ธ LimitedโŒ 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.

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.