{"record":{"id":"8fe3fa079a52a1dc","repo":"oxc-project/oxc","slug":"checked-should-be-used-with-either-onchange-or","errorCode":null,"errorMessage":"`checked` should be used with either `onChange` or `readOnly`.","messagePattern":"`checked` should be used with either `onChange` or `readOnly`\\.","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/react/checked_requires_onchange_or_readonly.rs","lineNumber":19,"sourceCode":"use oxc_ast::{\n    AstKind,\n    ast::{Argument, JSXAttributeItem, ObjectPropertyKind},\n};\nuse oxc_diagnostics::OxcDiagnostic;\nuse oxc_macros::declare_oxc_lint;\nuse oxc_span::Span;\nuse schemars::JsonSchema;\nuse serde::Deserialize;\n\nuse crate::{\n    AstNode,\n    context::LintContext,\n    rule::{DefaultRuleConfig, Rule},\n    utils::{get_element_type, get_jsx_attribute_name, is_create_element_call},\n};\n\nfn missing_property(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"`checked` should be used with either `onChange` or `readOnly`.\")\n        .with_help(\"Add either `onChange` or `readOnly`.\")\n        .with_label(span)\n}\n\nfn exclusive_checked_attribute(checked_span: Span, default_checked_span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"Use either `checked` or `defaultChecked`, but not both.\")\n        .with_help(\"Remove either `checked` or `defaultChecked`.\")\n        .with_labels([checked_span, default_checked_span])\n}\n\n#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]\n#[serde(rename_all = \"camelCase\", default, deny_unknown_fields)]\npub struct CheckedRequiresOnchangeOrReadonly {\n    /// Ignore the requirement to provide either `onChange` or `readOnly` when the `checked` prop is present.\n    ignore_missing_properties: bool,\n    /// Ignore the restriction that `checked` and `defaultChecked` should not be used together.\n    ignore_exclusive_checked_attribute: bool,\n}","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/react/checked_requires_onchange_or_readonly.rs#L1-L37","documentation":"Diagnostic from the oxlint rule `react/checked-requires-onchange-or-readonly` (plugin `react`, category `pedantic`). It fires on `<input>` elements (element type resolved via `get_element_type`, so components mapping to `input` count; `createElement('input', ...)` too) that carry a `checked` attribute but no `onChange` and no `readOnly` attribute. This mirrors React's controlled-component contract: a `checked` input without `onChange` is a frozen controlled field, and React itself logs a dev warning for it. Only explicit JSX attributes named `checked`/`onChange`/`readOnly` satisfy the fold - spread attributes do not. The `ignoreMissingProperties` option disables this check.","triggerScenarios":"`<input type=\"checkbox\" checked />`; `<input type=\"checkbox\" checked={done} />`; `React.createElement('input', { checked: true })`; checked radio inputs without handlers.","commonSituations":"Display-only checkboxes in admin tables; porting HTML prototypes where React semantics were not considered; forgetting that `defaultChecked` (not `checked`) is the uncontrolled variant.","solutions":["Add an `onChange` handler to make it a working controlled input","Add `readOnly` when the value is intentionally static and displayed","Switch to `defaultChecked` for uncontrolled initial state","If props are supplied via spread, add `ignoreMissingProperties: true` to the rule config"],"exampleFix":"// before\n<input type=\"checkbox\" checked={done} />\n\n// after\n<input type=\"checkbox\" checked={done} onChange={toggleDone} />","handlingStrategy":"validation","validationCode":"npx oxlint --react/checked-requires-onchange-or-readonly src/","typeGuard":"// For library authors validating props before rendering:\nfunction isControlledInputComplete(props: {\n  checked?: boolean;\n  defaultChecked?: boolean;\n  onChange?: () => void;\n  readOnly?: boolean;\n}): boolean {\n  return props.checked === undefined\n    || Boolean(props.onChange)\n    || Boolean(props.readOnly);\n}","tryCatchPattern":null,"preventionTips":["Controlled input = `checked` + `onChange`; static display = `checked` + `readOnly`; uncontrolled = `defaultChecked`","Watch React's own dev warning 'You provided a `checked` prop to a form field without an `onChange` handler' - same contract","Note that spread props do not satisfy the rule - declare `onChange`/`readOnly` explicitly or set `ignoreMissingProperties`"],"tags":["react","jsx","lint","controlled-components","forms","oxlint"],"backgroundTag":"controlled-input-without-onchange","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}