Skip to main content
ESLint Interlace
Plugin: react-featuresRules

require-default-props

require-default-props rule

Keywords: React, defaultProps, optional props, type safety, component API, ESLint rule, LLM-optimized

Require default props for optional props. This rule is part of eslint-plugin-react-features.

Quick Summary

AspectDetails
SeverityWarning (robustness)
Auto-Fix❌ No (requires default values)
CategoryReact
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForReact components with optional props

Rule Details

Non-required props should have corresponding default values in defaultProps. This ensures predictable component behavior when props are omitted.

Why This Matters

IssueImpactSolution
🔄 Undefined propsundefined passed to childrenDefine defaultProps
🐛 Conditional renderingExtra null checks neededGuaranteed values
🔍 Component APIUnclear expected behaviorDefaults document intent

Examples

❌ Incorrect

import PropTypes from 'prop-types';

// BAD: Optional props without defaults
class Button extends React.Component {
  static propTypes = {
    label: PropTypes.string.isRequired,
    variant: PropTypes.string,     // Optional but no default!
    size: PropTypes.string,        // Optional but no default!
    disabled: PropTypes.bool,      // Optional but no default!
  };
  
  render() {
    // Need null checks everywhere
    const { label, variant, size, disabled } = this.props;
    return (
      <button 
        className={variant ? `btn-${variant}` : 'btn-default'}
        disabled={disabled ?? false}
      >
        {label}
      </button>
    );
  }
}

✅ Correct

import PropTypes from 'prop-types';

// GOOD: All optional props have defaults
class Button extends React.Component {
  static propTypes = {
    label: PropTypes.string.isRequired,
    variant: PropTypes.string,
    size: PropTypes.string,
    disabled: PropTypes.bool,
  };
  
  static defaultProps = {
    variant: 'primary',
    size: 'medium',
    disabled: false,
  };
  
  render() {
    // No null checks needed - values guaranteed
    const { label, variant, size, disabled } = this.props;
    return (
      <button className={`btn-${variant} btn-${size}`} disabled={disabled}>
        {label}
      </button>
    );
  }
}

// BETTER: Functional component with default parameters
function Button({
  label,
  variant = 'primary',
  size = 'medium',
  disabled = false,
}) {
  return (
    <button className={`btn-${variant} btn-${size}`} disabled={disabled}>
      {label}
    </button>
  );
}

Button.propTypes = {
  label: PropTypes.string.isRequired,
  variant: PropTypes.string,
  size: PropTypes.string,
  disabled: PropTypes.bool,
};

Options

OptionTypeDefaultDescription
forbidDefaultForRequiredbooleanfalseError if required prop has default

Configuration with Options

{
  rules: {
    'react-features/require-default-props': ['warn', {
      forbidDefaultForRequired: true  // Flag unnecessary defaults
    }]
  }
}

Configuration Examples

Basic Usage

{
  rules: {
    'react-features/require-default-props': 'warn'
  }
}

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.

Cross-Module Data Flow

Why: ESLint rules analyze one file at a time. Values imported from other modules cannot be traced.

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

Mitigation: Apply the same rule to imported modules. Use module boundaries and explicit exports.