{"record":{"id":"90c37a5cbc96a14b","repo":"oxc-project/oxc","slug":"prop-name-is-a-reserved-attribute-and-cannot-b","errorCode":null,"errorMessage":"'{prop_name}' is a reserved attribute and cannot be used as props.","messagePattern":"'(.+?)' is a reserved attribute and cannot be used as props\\.","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"error","filePath":"crates/oxc_linter/src/rules/vue/no_reserved_props.rs","lineNumber":32,"sourceCode":"\nuse crate::{\n    AstNode,\n    context::LintContext,\n    frameworks::FrameworkOptions,\n    rule::{DefaultRuleConfig, Rule},\n    utils::{\n        for_each_define_props_type_signature, is_vue_component_options_object,\n        vue_casing::kebab_case,\n    },\n};\n\n/// Reserved attribute names that cannot be used as prop names, by Vue version.\nconst RESERVED_VUE3: &[&str] = &[\"key\", \"ref\"];\nconst RESERVED_VUE2: &[&str] =\n    &[\"key\", \"ref\", \"is\", \"slot\", \"slot-scope\", \"slotScope\", \"class\", \"style\"];\n\nfn no_reserved_props_diagnostic(prop_name: &str, span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(format!(\n        \"'{prop_name}' is a reserved attribute and cannot be used as props.\"\n    ))\n    .with_label(span)\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]\n#[serde(rename_all = \"camelCase\", default, deny_unknown_fields)]\nstruct NoReservedPropsConfig {\n    /// Vue major version whose reserved attribute set is applied. Vue 2 reserves\n    /// more names (`is`, `slot`, `class`, `style`, ...) than Vue 3.\n    #[serde(deserialize_with = \"deserialize_vue_version\")]\n    vue_version: u8,\n}\n\nimpl Default for NoReservedPropsConfig {\n    fn default() -> Self {\n        Self { vue_version: 3 }\n    }","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/vue/no_reserved_props.rs#L14-L50","documentation":"The vue/no-reserved-props rule reports props whose names collide with reserved template attributes. The source defines the sets per version: Vue 3 reserves `key` and `ref`; Vue 2 additionally reserves `is`, `slot`, `slot-scope`, `slotScope`, `class` and `style`. Declaring such a prop does not work — the template compiler consumes the attribute for its own purposes and never passes it as a prop. Which set applies is chosen by the rule's `vueVersion` option (deserialized via deserialize_vue_version); the rule checks both object-syntax components (is_vue_component_options_object) and `defineProps` type signatures, comparing kebab-cased names.","triggerScenarios":"Declaring `props: ['key']`, `props: ['ref']`, or in Vue 2 mode `is`/`slot`/`class`/`style`, including camelCase forms like `slotScope` and `defineProps<{ is: boolean }>()` signatures once kebab-cased.","commonSituations":"Components modeling HTML concepts (`class` for CSS, `is` for dynamic types) ported into Vue props; migrating Vue 2 components to Vue 3 while linting with the wrong `vueVersion`; generic table/list components that accept a `key` prop.","solutions":["Rename the prop to a non-reserved name (e.g. `itemKey`, `variant`, `cssClass`).","If you need the native attribute behavior (`class`/`style`/`is`), rely on Vue's fallthrough attributes instead of declaring a prop.","Verify the rule's `vueVersion` option matches your project (Vue 2 reserves more names than Vue 3).","Re-run oxlint to confirm."],"exampleFix":"// before\nexport default {\n  props: ['key'] // reserved attribute\n}\n\n// after\nexport default {\n  props: ['itemKey']\n}","handlingStrategy":"validation","validationCode":"// guard prop declarations at authoring time\nconst RESERVED = ['key', 'ref', 'is', 'slot', 'slot-scope', 'slotScope', 'class', 'style'];\nfunction assertProps(props) {\n  for (const name of Object.keys(props)) {\n    if (RESERVED.includes(name)) throw new Error(`prop '${name}' is a reserved attribute`);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set the rule's `vueVersion` to match your project (Vue 2 reserves more attribute names).","Use fallthrough attributes for class/style instead of declaring them as props.","Rename key/ref/is props to itemKey/elementRef/componentIs style names."],"tags":["vue","props","lint","reserved-names","template"],"backgroundTag":"reserved-name-collision","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"}