Repository: sveltejs/svelte (JavaScript)
Date: 2020-12-29 08:26:59+00:00
Task type: Feature

Issue:
Warn if a recovering React user accidentally types 'className' instead of 'class'
[Slightly tongue-in-cheek](https://twitter.com/AdamRackis/status/1337821236622204930), but I've actually hit this myself occasionally while porting React components to Svelte:

<img width="592" alt="Screen Shot 2020-12-12 at 1 42 47 PM" src="https://user-images.githubusercontent.com/1162160/101992267-f4c50d80-3c7f-11eb-8991-2b696e4d7504.png">


Issue discussion:
Opportunities for zing should never be passed up.
![image](https://user-images.githubusercontent.com/16696352/101992704-2a1f2a80-3c83-11eb-83a9-ca55b8c6b8d1.png)

That is a property not an attribute.

Edit: This was in response to a now deleted comment.
I think this also applies to `for` instead of `htmlFor` and `on:input` instead of `onChange`

Solution patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
 
 ## Unreleased
 
+* Warn when using `className` or `htmlFor` attributes ([#5777](https://github.com/sveltejs/svelte/issues/5777))
 * Fix checkbox `bind:group` in nested `{#each}` contexts ([#5811](https://github.com/sveltejs/svelte/issues/5811))
 * Add graphics roles as known ARIA roles ([#5822](https://github.com/sveltejs/svelte/pull/5822))
 
diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts
--- a/src/compiler/compile/nodes/Element.ts
+++ b/src/compiler/compile/nodes/Element.ts
@@ -93,6 +93,11 @@ const passive_events = new Set([
 	'touchcancel'
 ]);
 
+const react_attributes = new Map([
+	['className', 'class'],
+	['htmlFor', 'for']
+]);
+
 function get_namespace(parent: Element, element: Element, explicit_namespace: string) {
 	const parent_element = parent.find_nearest(/^Element/);
 
@@ -444,6 +449,13 @@ export default class Element extends Node {
 				});
 			}
 
+			if (react_attributes.has(attribute.name)) {
+				component.warn(attribute, {
+					code: 'invalid-html-attribute',
+					message: `'${attribute.name}' is not a valid HTML attribute. Did you mean '${react_attributes.get(attribute.name)}'?`
+				});
+			}
+
 			attribute_map.set(attribute.name, attribute);
 		});
 	}


Test patch:
diff --git a/test/validator/samples/use-the-platform/input.svelte b/test/validator/samples/use-the-platform/input.svelte
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/use-the-platform/input.svelte
@@ -0,0 +1,2 @@
+<div className="abc"></div>
+<label htmlFor="i"><input /></label>
\ No newline at end of file
diff --git a/test/validator/samples/use-the-platform/warnings.json b/test/validator/samples/use-the-platform/warnings.json
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/use-the-platform/warnings.json
@@ -0,0 +1,32 @@
+[
+	{
+		"code": "invalid-html-attribute",
+		"message": "'className' is not a valid HTML attribute. Did you mean 'class'?",
+		"pos": 5,
+		"start": {
+			"character": 5,
+			"column": 5,
+			"line": 1
+		},
+		"end": {
+			"character": 20,
+			"column": 20,
+			"line": 1
+		}
+	},
+	{
+		"code": "invalid-html-attribute",
+		"message": "'htmlFor' is not a valid HTML attribute. Did you mean 'for'?",
+		"pos": 35,
+		"start": {
+			"character": 35,
+			"column": 7,
+			"line": 2
+		},
+		"end": {
+			"character": 46,
+			"column": 18,
+			"line": 2
+		}
+	}
+]