diff --git a/src/generators/dom/visitors/Element/Attribute.ts b/src/generators/dom/visitors/Element/Attribute.ts
index 7fbb73394bf5..14f68b5a5e01 100644
--- a/src/generators/dom/visitors/Element/Attribute.ts
+++ b/src/generators/dom/visitors/Element/Attribute.ts
@@ -22,8 +22,7 @@ export default function visitAttribute(
const isIndirectlyBoundValue =
name === 'value' &&
(node.name === 'option' || // TODO check it's actually bound
- (node.name === 'input' &&
- /^(checkbox|radio)$/.test(getStaticAttributeValue(node, 'type'))));
+ (node.name === 'input' && node.attributes.find((attribute: Node) => attribute.type === 'Binding' && /checked|group/.test(attribute.name))));
const propertyName = isIndirectlyBoundValue
? '__value'
@@ -133,8 +132,8 @@ export default function visitAttribute(
const statement = propertyName
? `${state.parentNode}.${propertyName} = ${value};`
: `${generator.helper(
- method
- )}( ${state.parentNode}, '${name}', ${value} );`;
+ method
+ )}( ${state.parentNode}, '${name}', ${value} );`;
block.builders.create.addLine(statement);
diff --git a/src/validate/html/validateElement.ts b/src/validate/html/validateElement.ts
index 081fea60288b..6433ba8a2b9e 100644
--- a/src/validate/html/validateElement.ts
+++ b/src/validate/html/validateElement.ts
@@ -25,6 +25,8 @@ export default function validateElement(validator: Validator, node: Node) {
attribute.start
);
}
+
+ checkTypeAttribute(validator, node);
} else if (name === 'checked') {
if (node.name !== 'input') {
validator.error(
@@ -33,7 +35,7 @@ export default function validateElement(validator: Validator, node: Node) {
);
}
- if (getType(validator, node) !== 'checkbox') {
+ if (checkTypeAttribute(validator, node) !== 'checkbox') {
validator.error(
`'checked' binding can only be used with `,
attribute.start
@@ -47,7 +49,7 @@ export default function validateElement(validator: Validator, node: Node) {
);
}
- const type = getType(validator, node);
+ const type = checkTypeAttribute(validator, node);
if (type !== 'checkbox' && type !== 'radio') {
validator.error(
@@ -128,7 +130,7 @@ export default function validateElement(validator: Validator, node: Node) {
});
}
-function getType(validator: Validator, node: Node) {
+function checkTypeAttribute(validator: Validator, node: Node) {
const attribute = node.attributes.find(
(attribute: Node) => attribute.name === 'type'
);
@@ -139,7 +141,7 @@ function getType(validator: Validator, node: Node) {
}
if (attribute.value.length > 1 || attribute.value[0].type !== 'Text') {
- validator.error(`'type attribute cannot be dynamic`, attribute.start);
+ validator.error(`'type' attribute cannot be dynamic if input uses two-way binding`, attribute.start);
}
return attribute.value[0].data;
diff --git a/test/runtime/samples/attribute-dynamic-type/_config.js b/test/runtime/samples/attribute-dynamic-type/_config.js
new file mode 100644
index 000000000000..93a4e28acd6f
--- /dev/null
+++ b/test/runtime/samples/attribute-dynamic-type/_config.js
@@ -0,0 +1,19 @@
+export default {
+ 'skip-ssr': true,
+
+ data: {
+ inputType: 'text',
+ inputValue: 42
+ },
+
+ html: ``,
+
+ test(assert, component, target) {
+ const input = target.querySelector('input');
+ assert.equal(input.type, 'text');
+ assert.equal(input.value, '42');
+
+ component.set({ inputType: 'number' });
+ assert.equal(input.type, 'number');
+ }
+};
diff --git a/test/runtime/samples/attribute-dynamic-type/main.html b/test/runtime/samples/attribute-dynamic-type/main.html
new file mode 100644
index 000000000000..5bafd96cb361
--- /dev/null
+++ b/test/runtime/samples/attribute-dynamic-type/main.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/test/validator/samples/binding-input-static-type/errors.json b/test/validator/samples/binding-input-static-type/errors.json
new file mode 100644
index 000000000000..fbc8284ec4d6
--- /dev/null
+++ b/test/validator/samples/binding-input-static-type/errors.json
@@ -0,0 +1,8 @@
+[{
+ "message": "'type' attribute cannot be dynamic if input uses two-way binding",
+ "loc": {
+ "line": 1,
+ "column": 24
+ },
+ "pos": 24
+}]
\ No newline at end of file
diff --git a/test/validator/samples/binding-input-static-type/input.html b/test/validator/samples/binding-input-static-type/input.html
new file mode 100644
index 000000000000..4f54010bdc4a
--- /dev/null
+++ b/test/validator/samples/binding-input-static-type/input.html
@@ -0,0 +1 @@
+
\ No newline at end of file