Skip to main content
interlace
Plugin: react-featuresRules

static-property-placement

static-property-placement rule

Enforce static property placement in React class components. This rule is part of eslint-plugin-react-features.

Quick Summary

AspectDetails
SeverityWarning (organization)
Auto-Fix❌ No (requires reordering)
CategoryReact
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForReact class components with consistent structure

Rule Details

Enforces consistent placement and grouping of static properties like propTypes, defaultProps, contextTypes, and lifecycle static methods.

Why This Matters

IssueImpactSolution
🔄 Scattered staticsProperties hard to findGroup together
🐛 Inconsistent placementDifferent patterns across codebaseStandardize location
🔍 Review difficultyTime wasted searchingPredictable structure

Default Property Groups

Group NameProperties
propTypespropTypes, defaultProps, childContextTypes, contextTypes, contextType
lifecyclegetDerivedStateFromProps, getDerivedStateFromError

Examples

❌ Incorrect

class UserCard extends React.Component {
  static propTypes = { name: PropTypes.string };
  static getDerivedStateFromProps() {
    return null;
  }
  // BAD: the propTypes group resumes after the lifecycle group
  static defaultProps = { name: 'Guest' };
}

A group is broken when one of its statics comes after a static of a different group that followed the first. A static in no group never breaks one. Names are read in every spelling (static ['defaultProps']), and the class must extend React's Component or PureComponent, by binding.

✅ Correct

class UserCard extends React.Component {
  // GOOD: All prop-related statics grouped together
  static propTypes = {
    name: PropTypes.string.isRequired,
    email: PropTypes.string,
  };
  
  static defaultProps = {
    name: 'Guest',
    email: '',
  };
  
  static contextTypes = {
    theme: PropTypes.object
  };
  
  // GOOD: Lifecycle statics grouped together
  static getDerivedStateFromProps(props, state) {
    if (props.name !== state.prevName) {
      return { name: props.name, prevName: props.name };
    }
    return null;
  }
  
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  
  // Instance properties after statics
  state = { loading: true, name: '' };
  
  componentDidMount() {
    this.fetchData();
  }
  
  render() {
    return <div>{this.state.name}</div>;
  }
}

// BETTER: Use functional components
function UserCard({ name = 'Guest', email = '' }) {
  const theme = useContext(ThemeContext);
  return <div style={theme}>{name}</div>;
}

UserCard.propTypes = {
  name: PropTypes.string,
  email: PropTypes.string,
};

Options

OptionTypeDefaultDescription
propertyGroupsarraySee defaultsProperty groups; replaces the default groups
childClassstring'first'Accepted for compatibility; it has no effect

Configuration with Options

{
  rules: {
    'react-features/static-property-placement': ['warn', {
      propertyGroups: [
        {
          name: 'propTypes',
          properties: ['propTypes', 'defaultProps', 'contextTypes']
        },
        {
          name: 'lifecycle',
          properties: ['getDerivedStateFromProps', 'getDerivedStateFromError']
        },
        {
          name: 'custom',
          properties: ['displayName', 'navigationOptions']
        }
      ],
      childClass: 'first'
    }]
  }
}

Configuration Examples

Basic Usage

{
  rules: {
    'react-features/static-property-placement': 'warn'
  }
}

Further Reading

Known False Negatives

  • Statics assigned after the class (Card.propTypes = …) are not checked.
  • A static in no group never breaks a group.

Use this rule

npm install -D oxlint-plugin-react-features
.oxlintrc.json
{  "jsPlugins": ["oxlint-plugin-react-features"],  "rules": {    "react-features/static-property-placement": "error"  }}
vite.config.ts
import { defineConfig } from 'vite-plus';export default defineConfig({  lint: {    jsPlugins: ['oxlint-plugin-react-features'],    rules: {      'react-features/static-property-placement': '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.