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
| Aspect | Details |
|---|---|
| Severity | Warning (robustness) |
| Auto-Fix | ❌ No (requires default values) |
| Category | React |
| ESLint MCP | ✅ Optimized for ESLint MCP integration |
| Best For | React 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
| Issue | Impact | Solution |
|---|---|---|
| 🔄 Undefined props | undefined passed to children | Define defaultProps |
| 🐛 Conditional rendering | Extra null checks needed | Guaranteed values |
| 🔍 Component API | Unclear expected behavior | Defaults 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
| Option | Type | Default | Description |
|---|---|---|---|
forbidDefaultForRequired | boolean | false | Error 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'
}
}Related Rules
prop-types- Enforce PropTypesdefault-props-match-prop-types- Type consistency
Further Reading
- Default Props - React docs
- PropTypes Validation - Type checking
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 analyzedMitigation: 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 trackedMitigation: Apply the same rule to imported modules. Use module boundaries and explicit exports.