diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts
index 7a70e603a7..915941d280 100644
--- a/src/compiler/compile/nodes/Element.ts
+++ b/src/compiler/compile/nodes/Element.ts
@@ -507,6 +507,16 @@ export default class Element extends Node {
}
}
+ if (this.name === 'label') {
+ const has_input_child = this.children.some(i => (i instanceof Element && i.name === 'input' ));
+ if (!attribute_map.has('for') && !has_input_child) {
+ component.warn(this, {
+ code: `a11y-label-has-associated-control`,
+ message: `A11y: A form label must be associated with a control.`
+ });
+ }
+ }
+
if (a11y_no_onchange.has(this.name)) {
if (handlers_map.has('change') && !handlers_map.has('blur')) {
component.warn(this, {
diff --git a/test/validator/samples/a11y-label-has-associated-control/input.svelte b/test/validator/samples/a11y-label-has-associated-control/input.svelte
new file mode 100644
index 0000000000..92458f4625
--- /dev/null
+++ b/test/validator/samples/a11y-label-has-associated-control/input.svelte
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/test/validator/samples/a11y-label-has-associated-control/warnings.json b/test/validator/samples/a11y-label-has-associated-control/warnings.json
new file mode 100644
index 0000000000..5e9bb9c15a
--- /dev/null
+++ b/test/validator/samples/a11y-label-has-associated-control/warnings.json
@@ -0,0 +1,32 @@
+[
+ {
+ "code": "a11y-label-has-associated-control",
+ "end": {
+ "character": 16,
+ "column": 16,
+ "line": 1
+ },
+ "message": "A11y: A form label must be associated with a control.",
+ "pos": 0,
+ "start": {
+ "character": 0,
+ "column": 0,
+ "line": 1
+ }
+ },
+ {
+ "code": "a11y-label-has-associated-control",
+ "end": {
+ "character": 113,
+ "column": 30,
+ "line": 5
+ },
+ "message": "A11y: A form label must be associated with a control.",
+ "pos": 83,
+ "start": {
+ "character": 83,
+ "column": 0,
+ "line": 5
+ }
+ }
+]