oxc-project/oxc · warning · OxcDiagnostic
Use either `checked` or `defaultChecked`, but not both.
Error message
Use either `checked` or `defaultChecked`, but not both.
What it means
Diagnostic from the oxlint rule `react/checked-requires-onchange-or-readonly` (plugin `react`, category `pedantic`). It fires when an `<input>` carries BOTH `checked` and `defaultChecked` attributes. The two are the controlled and uncontrolled ways to set checked state and are mutually exclusive; React ignores one of them and the component's behavior becomes unpredictable across renders. The diagnostic carries two labels - one on each attribute span - and the `ignoreExclusiveCheckedAttribute` option disables the check.
Source
Thrown at crates/oxc_linter/src/rules/react/checked_requires_onchange_or_readonly.rs:25
use oxc_span::Span;
use schemars::JsonSchema;
use serde::Deserialize;
use crate::{
AstNode,
context::LintContext,
rule::{DefaultRuleConfig, Rule},
utils::{get_element_type, get_jsx_attribute_name, is_create_element_call},
};
fn missing_property(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("`checked` should be used with either `onChange` or `readOnly`.")
.with_help("Add either `onChange` or `readOnly`.")
.with_label(span)
}
fn exclusive_checked_attribute(checked_span: Span, default_checked_span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Use either `checked` or `defaultChecked`, but not both.")
.with_help("Remove either `checked` or `defaultChecked`.")
.with_labels([checked_span, default_checked_span])
}
#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
pub struct CheckedRequiresOnchangeOrReadonly {
/// Ignore the requirement to provide either `onChange` or `readOnly` when the `checked` prop is present.
ignore_missing_properties: bool,
/// Ignore the restriction that `checked` and `defaultChecked` should not be used together.
ignore_exclusive_checked_attribute: bool,
}
declare_oxc_lint!(
/// ### What it does
///
/// This rule enforces `onChange` or `readOnly` attribute for checked property of input elements.
/// It also warns when `checked` and `defaultChecked` properties are used together.View on GitHub (pinned to e1e7af627c)
Solutions
- Keep `checked` (controlled) and delete `defaultChecked`
- Keep `defaultChecked` (uncontrolled initial value) and delete `checked`
- If a wrapper may receive both, filter one out before spreading onto the input
Example fix
// before
<input type="checkbox" checked={done} defaultChecked={false} onChange={toggleDone} />
// after
<input type="checkbox" checked={done} onChange={toggleDone} /> Defensive patterns
Strategy: validation
Validate before calling
npx oxlint --react/checked-requires-onchange-or-readonly src/
Type guard
// Guard for wrapper components before spreading props:
const hasExclusiveCheckedConflict = (p: {
checked?: unknown;
defaultChecked?: unknown;
}): boolean => 'checked' in p && 'defaultChecked' in p; Prevention
- Choose controlled (`checked`) or uncontrolled (`defaultChecked`) per component - never both
- In wrappers that forward props, strip one of the two before spreading onto `<input>`
- React's docs treat these as mutually exclusive; follow the same rule in prop types (omit one)
When it happens
Trigger: `<input type="checkbox" checked defaultChecked />`; `<input type="radio" checked={a} defaultChecked={b} />`; `createElement('input', { checked: true, defaultChecked: true })`.
Common situations: Merge of a default-initialization prop with a controlled prop; copy-paste between controlled and uncontrolled components; wrapper components forwarding both props to the inner input.
Related errors
- `checked` should be used with either `onChange` or `readOnly
- `button` elements must have an explicit `type` attribute.
- `button` elements must have a valid `type` attribute.
- Component definition is missing display name.
- Invalid handler name: {handler_name}
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/7057232ced7cb595.
Report an issue: GitHub.