{"record":{"id":"aa89c48959bd02e3","repo":"oxc-project/oxc","slug":"button-elements-must-have-a-valid-type-attribu","errorCode":null,"errorMessage":"`button` elements must have a valid `type` attribute.","messagePattern":"`button` elements must have a valid `type` attribute\\.","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/react/button_has_type.rs","lineNumber":27,"sourceCode":"    ast::{\n        Argument, Expression, JSXAttributeItem, JSXAttributeValue, JSXElementName,\n        ObjectPropertyKind,\n    },\n};\nuse oxc_diagnostics::OxcDiagnostic;\nuse oxc_macros::declare_oxc_lint;\nuse oxc_span::{GetSpan, Span};\nuse schemars::JsonSchema;\nuse serde::Deserialize;\n\nfn missing_type_prop(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"`button` elements must have an explicit `type` attribute.\")\n        .with_help(\"Add a `type` attribute to the `button` element.\")\n        .with_label(span)\n}\n\nfn invalid_type_prop(span: Span, allowed_types: &str) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"`button` elements must have a valid `type` attribute.\")\n        .with_help(format!(\n            \"Change the `type` attribute to one of the allowed values: {allowed_types}.\"\n        ))\n        .with_label(span)\n}\n\n#[derive(Debug, Clone, JsonSchema, Deserialize)]\n#[serde(rename_all = \"camelCase\", default, deny_unknown_fields)]\npub struct ButtonHasType {\n    /// If true, allow `type=\"button\"`.\n    button: bool,\n    /// If true, allow `type=\"submit\"`.\n    submit: bool,\n    /// If true, allow `type=\"reset\"`.\n    reset: bool,\n}\n\nimpl Default for ButtonHasType {","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/react/button_has_type.rs#L9-L45","documentation":"Diagnostic from the oxlint rule `react/button-has-type` (plugin `react`, category `restriction`). It fires when a `<button>` (or `createElement('button', ...)`) HAS a `type` attribute but its value is not statically one of the enabled literals. The rule accepts string literals, template literals with a single quasi (no interpolation), expression containers wrapping those, and conditional expressions where BOTH branches are valid. Anything else - identifiers (`type={foo}`), interpolated templates, other expression types - is rejected because the value cannot be proven. The `button`/`submit`/`reset` config flags (all default `true`) narrow the allowed set, and the help text lists the enabled values (e.g. turning `reset: false` on makes `type=\"reset\"` invalid).","triggerScenarios":"`<button type=\"foo\" />`; `<button type={foo} />` (dynamic identifier); `<button type={`button${suffix}`} />`; `type={cond ? \"button\" : \"reset\"}` with `reset: false`; `createElement(\"button\", { type: \"foo\" })`.","commonSituations":"Type driven by a variable or config map; template literals built at runtime; teams restricting submit buttons in form-heavy codebases via the config flags.","solutions":["Use an allowed literal: `type=\"button\"`, `type=\"submit\"`, or `type=\"reset\"`","For dynamic values, express both possibilities as literals: `type={isPrimary ? 'submit' : 'button'}`","If you disabled a value in config (e.g. `reset: false`), either re-enable it or stop using that value","If the value is genuinely unresolvable statically, widen with a comment/directive or move the choice into a wrapper component with literal props"],"exampleFix":"// before\n<button type={btnKind}>Go</button>\n\n// after\n<button type={btnKind === 'primary' ? 'submit' : 'button'}>Go</button>","handlingStrategy":"validation","validationCode":"npx oxlint --react/button-has-type src/","typeGuard":"// Constrain button types at the type level:\ntype ButtonType = 'button' | 'submit' | 'reset';\nconst isButtonType = (v: string): v is ButtonType =>\n  v === 'button' || v === 'submit' || v === 'reset';\n// component prop: { type: ButtonType } - invalid literals never compile","tryCatchPattern":null,"preventionTips":["Type button props as `'button' | 'submit' | 'reset'` in your component library","Express dynamic choices as conditionals with literal branches so the rule (and readers) can resolve them","Keep the `button`/`submit`/`reset` config flags in sync with your design-system rules"],"tags":["react","jsx","html","lint","forms","oxlint"],"backgroundTag":"invalid-button-type-attribute","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}