Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Switch to GitLab Next
Sign in / Register
Toggle navigation
Menu
Open sidebar
html-validate
html-validate
Commits
23ee19ea
Commit
23ee19ea
authored
Jun 14, 2021
by
David Sveningsson
Browse files
feat: new rule `input-attributes`
fixes
#119
parent
25f6bd7b
Pipeline
#320822076
passed with stages
in 9 minutes and 41 seconds
Changes
12
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
docs/rules/__tests__/__snapshots__/input-attributes.md.spec.ts.snap
0 → 100644
View file @
23ee19ea
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs/rules/input-attributes.md inline validation: correct 1`] = `Array []`;
exports[`docs/rules/input-attributes.md inline validation: incorrect 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 20,
"context": Object {
"attribute": "step",
"type": "text",
},
"line": 1,
"message": "Attribute \\"step\\" is not allowed on <input type=\\"text\\">",
"offset": 19,
"ruleId": "input-attributes",
"ruleUrl": "https://html-validate.org/rules/input-attributes.html",
"selector": "input",
"severity": 2,
"size": 4,
},
],
"source": "<input type=\\"text\\" step=\\"5\\">",
"warningCount": 0,
},
]
`;
docs/rules/__tests__/input-attributes.md.spec.ts
0 → 100644
View file @
23ee19ea
import
HtmlValidate
from
"
../../../src/htmlvalidate
"
;
const
markup
:
{
[
key
:
string
]:
string
}
=
{};
markup
[
"
incorrect
"
]
=
`<input type="text" step="5">`
;
markup
[
"
correct
"
]
=
`<input type="number" step="5">`
;
describe
(
"
docs/rules/input-attributes.md
"
,
()
=>
{
it
(
"
inline validation: incorrect
"
,
()
=>
{
expect
.
assertions
(
1
);
const
htmlvalidate
=
new
HtmlValidate
({
"
rules
"
:{
"
input-attributes
"
:
"
error
"
}});
const
report
=
htmlvalidate
.
validateString
(
markup
[
"
incorrect
"
]);
expect
(
report
.
results
).
toMatchSnapshot
();
});
it
(
"
inline validation: correct
"
,
()
=>
{
expect
.
assertions
(
1
);
const
htmlvalidate
=
new
HtmlValidate
({
"
rules
"
:{
"
input-attributes
"
:
"
error
"
}});
const
report
=
htmlvalidate
.
validateString
(
markup
[
"
correct
"
]);
expect
(
report
.
results
).
toMatchSnapshot
();
});
});
docs/rules/attr-pattern.md
View file @
23ee19ea
...
...
@@ -57,3 +57,7 @@ For instance, when configured with `{"pattern": ["[a-z0-9-]+", "myprefix-.+"]}`
By default attributes on foreign elements (such as
`<svg>`
and
`<math>`
) are ignored as they follow their own specifications.
Disable this option if you want to validate attributes on foreign elements as well.
## Version history
-
v%version% - Rule added.
docs/rules/input-attributes.md
0 → 100644
View file @
23ee19ea
---
docType
:
rule
name
:
input-attributes
category
:
content-model
summary
:
Validates usage of input attributes
---
# Validates usage of input attributes (`input-attributes`)
The
`<input>`
element uses the
`type`
attribute to set what type of input field it is.
Depending on what type of input field it is many other attributes is allowed or disallowed.
For instance, the
`step`
attribute can be used with numerical fields but not with textual input.
This rule validates the usage of these attributes, ensuring the attributes are used only in the proper context.
See
[
HTML5 specification
][
whatwg
]
for a table of attributes and types.
[
whatwg
]:
https://html.spec.whatwg.org/multipage/input.html#concept-input-apply
## Rule details
Examples of
**incorrect**
code for this rule:
<validate
name=
"incorrect"
rules=
"input-attributes"
>
<input
type=
"text"
step=
"5"
>
</validate>
Examples of
**correct**
code for this rule:
<validate
name=
"correct"
rules=
"input-attributes"
>
<input
type=
"number"
step=
"5"
>
</validate>
## Version history
-
v%version% - Rule added.
elements/__snapshots__/html5.spec.ts.snap
View file @
23ee19ea
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/config/presets/recommended.ts
View file @
23ee19ea
...
...
@@ -24,6 +24,7 @@ const config: ConfigData = {
"
element-required-content
"
:
"
error
"
,
"
empty-heading
"
:
"
error
"
,
"
empty-title
"
:
"
error
"
,
"
input-attributes
"
:
"
error
"
,
"
long-title
"
:
"
error
"
,
"
meta-refresh
"
:
"
error
"
,
"
multiple-labeled-controls
"
:
"
error
"
,
...
...
src/rules/__snapshots__/input-attributes.spec.ts.snap
0 → 100644
View file @
23ee19ea
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`rule input-attributes should contain contextual documentation (invalid) 1`] = `
Object {
"description": "Attribute \`missing\` is not allowed on \`<input type=\\"text\\">\`
\`missing\` can only be used when \`type\` is:",
"url": "https://html-validate.org/rules/input-attributes.html",
}
`;
exports[`rule input-attributes should contain contextual documentation 1`] = `
Object {
"description": "Attribute \`alt\` is not allowed on \`<input type=\\"text\\">\`
\`alt\` can only be used when \`type\` is:
- \`image\`",
"url": "https://html-validate.org/rules/input-attributes.html",
}
`;
exports[`rule input-attributes should contain documentation 1`] = `
Object {
"description": "This attribute cannot be used with this input type.",
"url": "https://html-validate.org/rules/input-attributes.html",
}
`;
src/rules/index.ts
View file @
23ee19ea
...
...
@@ -26,6 +26,7 @@ import EmptyHeading from "./empty-heading";
import
EmptyTitle
from
"
./empty-title
"
;
import
HeadingLevel
from
"
./heading-level
"
;
import
IdPattern
from
"
./id-pattern
"
;
import
InputAttributes
from
"
./input-attributes
"
;
import
InputMissingLabel
from
"
./input-missing-label
"
;
import
LongTitle
from
"
./long-title
"
;
import
MetaRefresh
from
"
./meta-refresh
"
;
...
...
@@ -91,6 +92,7 @@ const bundledRules: Record<string, RuleConstructor<any, any>> = {
"
empty-title
"
:
EmptyTitle
,
"
heading-level
"
:
HeadingLevel
,
"
id-pattern
"
:
IdPattern
,
"
input-attributes
"
:
InputAttributes
,
"
input-missing-label
"
:
InputMissingLabel
,
"
long-title
"
:
LongTitle
,
"
meta-refresh
"
:
MetaRefresh
,
...
...
src/rules/input-attributes.spec.ts
0 → 100644
View file @
23ee19ea
import
HtmlValidate
from
"
../htmlvalidate
"
;
import
"
../matchers
"
;
import
{
processAttribute
}
from
"
../transform/mocks/attribute
"
;
describe
(
"
rule input-attributes
"
,
()
=>
{
let
htmlvalidate
:
HtmlValidate
;
beforeAll
(()
=>
{
htmlvalidate
=
new
HtmlValidate
({
root
:
true
,
rules
:
{
"
input-attributes
"
:
[
"
error
"
,
{
style
:
"
lowercase
"
}]
},
});
});
it
(
"
should not report error for other elements
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<div type="text" step="5"></div>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should not report error when attribute is correct
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<input type="number" step="5">
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should report error when incorrect attribute is used
"
,
()
=>
{
expect
.
assertions
(
2
);
const
report
=
htmlvalidate
.
validateString
(
'
<input type="text" step="5">
'
);
expect
(
report
).
toBeInvalid
();
expect
(
report
).
toHaveError
(
"
input-attributes
"
,
'
Attribute "step" is not allowed on <input type="text">
'
);
});
it
(
"
should handle when type is missing
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<input step="5">
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should handle when type is incomplete
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<input type step="5">
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should handle when type is dynamic
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<input dynamic-type="type" step="5">
'
,
{
processAttribute
,
});
expect
(
report
).
toBeValid
();
});
it
(
"
should contain documentation
"
,
()
=>
{
expect
.
assertions
(
1
);
htmlvalidate
=
new
HtmlValidate
({
root
:
true
,
rules
:
{
"
input-attributes
"
:
"
error
"
},
});
expect
(
htmlvalidate
.
getRuleDocumentation
(
"
input-attributes
"
)).
toMatchSnapshot
();
});
it
(
"
should contain contextual documentation
"
,
()
=>
{
expect
.
assertions
(
1
);
htmlvalidate
=
new
HtmlValidate
({
root
:
true
,
rules
:
{
"
input-attributes
"
:
"
error
"
},
});
const
context
=
{
attribute
:
"
alt
"
,
type
:
"
text
"
,
};
expect
(
htmlvalidate
.
getRuleDocumentation
(
"
input-attributes
"
,
null
,
context
)).
toMatchSnapshot
();
});
it
(
"
should contain contextual documentation (invalid)
"
,
()
=>
{
expect
.
assertions
(
1
);
htmlvalidate
=
new
HtmlValidate
({
root
:
true
,
rules
:
{
"
input-attributes
"
:
"
error
"
},
});
const
context
=
{
attribute
:
"
missing
"
,
type
:
"
text
"
,
};
expect
(
htmlvalidate
.
getRuleDocumentation
(
"
input-attributes
"
,
null
,
context
)).
toMatchSnapshot
();
});
});
src/rules/input-attributes.ts
0 → 100644
View file @
23ee19ea
/* eslint-disable sonarjs/no-duplicate-string */
import
{
TagReadyEvent
}
from
"
../event
"
;
import
{
Rule
,
RuleDocumentation
,
ruleDocumentationUrl
}
from
"
../rule
"
;
interface
RuleContext
{
attribute
:
string
;
type
:
string
;
}
const
restricted
:
Map
<
string
,
string
[]
>
=
new
Map
([
[
"
accept
"
,
[
"
file
"
]],
[
"
alt
"
,
[
"
image
"
]],
[
"
autocomplete
"
,
[
"
hidden
"
,
"
text
"
,
"
search
"
,
"
url
"
,
"
tel
"
,
"
email
"
,
"
password
"
,
"
date
"
,
"
month
"
,
"
week
"
,
"
time
"
,
"
datetime-local
"
,
"
number
"
,
"
range
"
,
"
color
"
,
],
],
[
"
capture
"
,
[
"
file
"
]],
[
"
checked
"
,
[
"
checkbox
"
,
"
radio
"
]],
[
"
dirname
"
,
[
"
text
"
,
"
search
"
]],
[
"
formaction
"
,
[
"
submit
"
,
"
image
"
]],
[
"
formenctype
"
,
[
"
submit
"
,
"
image
"
]],
[
"
formmethod
"
,
[
"
submit
"
,
"
image
"
]],
[
"
formnovalidate
"
,
[
"
submit
"
,
"
image
"
]],
[
"
formtarget
"
,
[
"
submit
"
,
"
image
"
]],
[
"
height
"
,
[
"
image
"
]],
[
"
list
"
,
[
"
text
"
,
"
search
"
,
"
url
"
,
"
tel
"
,
"
email
"
,
"
date
"
,
"
month
"
,
"
week
"
,
"
time
"
,
"
datetime-local
"
,
"
number
"
,
"
range
"
,
"
color
"
,
],
],
[
"
max
"
,
[
"
date
"
,
"
month
"
,
"
week
"
,
"
time
"
,
"
datetime-local
"
,
"
number
"
,
"
range
"
]],
[
"
maxlength
"
,
[
"
text
"
,
"
search
"
,
"
url
"
,
"
tel
"
,
"
email
"
,
"
password
"
]],
[
"
min
"
,
[
"
date
"
,
"
month
"
,
"
week
"
,
"
time
"
,
"
datetime-local
"
,
"
number
"
,
"
range
"
]],
[
"
minlength
"
,
[
"
text
"
,
"
search
"
,
"
url
"
,
"
tel
"
,
"
email
"
,
"
password
"
]],
[
"
multiple
"
,
[
"
email
"
,
"
file
"
]],
[
"
pattern
"
,
[
"
text
"
,
"
search
"
,
"
url
"
,
"
tel
"
,
"
email
"
,
"
password
"
]],
[
"
placeholder
"
,
[
"
text
"
,
"
search
"
,
"
url
"
,
"
tel
"
,
"
email
"
,
"
password
"
,
"
number
"
]],
[
"
readonly
"
,
[
"
text
"
,
"
search
"
,
"
url
"
,
"
tel
"
,
"
email
"
,
"
password
"
,
"
date
"
,
"
month
"
,
"
week
"
,
"
time
"
,
"
datetime-local
"
,
"
number
"
,
],
],
[
"
required
"
,
[
"
text
"
,
"
search
"
,
"
url
"
,
"
tel
"
,
"
email
"
,
"
password
"
,
"
date
"
,
"
month
"
,
"
week
"
,
"
time
"
,
"
datetime-local
"
,
"
number
"
,
"
checkbox
"
,
"
radio
"
,
"
file
"
,
],
],
[
"
size
"
,
[
"
text
"
,
"
search
"
,
"
url
"
,
"
tel
"
,
"
email
"
,
"
password
"
]],
[
"
src
"
,
[
"
image
"
]],
[
"
step
"
,
[
"
date
"
,
"
month
"
,
"
week
"
,
"
time
"
,
"
datetime-local
"
,
"
number
"
,
"
range
"
]],
[
"
width
"
,
[
"
image
"
]],
]);
function
isInput
(
event
:
TagReadyEvent
):
boolean
{
const
{
target
}
=
event
;
return
target
.
is
(
"
input
"
);
}
export
default
class
InputAttributes
extends
Rule
<
RuleContext
>
{
public
documentation
(
context
?:
RuleContext
):
RuleDocumentation
{
if
(
context
)
{
const
{
attribute
,
type
}
=
context
;
const
summary
=
`Attribute
\`
${
attribute
}
\`
is not allowed on
\`
<input type="
${
type
}
">
\`
\n`
;
const
details
=
`
\`
${
attribute
}
\`
can only be used when
\`
type
\`
is:`
;
const
list
=
restricted
.
get
(
attribute
)?.
map
((
it
)
=>
`-
\`
${
it
}
\`
`
)
??
[];
return
{
description
:
[
summary
,
details
,
...
list
].
join
(
"
\n
"
),
url
:
ruleDocumentationUrl
(
__filename
),
};
}
else
{
return
{
description
:
`This attribute cannot be used with this input type.`
,
url
:
ruleDocumentationUrl
(
__filename
),
};
}
}
public
setup
():
void
{
this
.
on
(
"
tag:ready
"
,
isInput
,
(
event
:
TagReadyEvent
)
=>
{
const
{
target
}
=
event
;
const
type
=
target
.
getAttribute
(
"
type
"
);
if
(
!
type
||
type
.
isDynamic
||
!
type
.
value
)
{
return
;
}
const
typeValue
=
type
.
value
.
toString
();
for
(
const
attr
of
target
.
attributes
)
{
const
validTypes
=
restricted
.
get
(
attr
.
key
);
if
(
!
validTypes
)
{
continue
;
}
if
(
validTypes
.
includes
(
typeValue
))
{
continue
;
}
const
context
:
RuleContext
=
{
attribute
:
attr
.
key
,
type
:
typeValue
,
};
const
message
=
`Attribute "
${
attr
.
key
}
" is not allowed on <input type="
${
typeValue
}
">`
;
this
.
report
(
target
,
message
,
attr
.
keyLocation
,
context
);
}
});
}
}
test-files/elements/input-invalid.html
View file @
23ee19ea
...
...
@@ -3,10 +3,10 @@
<!-- should not allow attributes -->
<input
type=
"text"
autofocus=
"foobar"
>
<input
type=
"
text
"
capture=
"foobar"
>
<input
type=
"
text
"
checked=
"foobar"
>
<input
type=
"
file
"
capture=
"foobar"
>
<input
type=
"
checkbox
"
checked=
"foobar"
>
<input
type=
"text"
disabled=
"foobar"
>
<input
type=
"
text
"
multiple=
"foobar"
>
<input
type=
"
file
"
multiple=
"foobar"
>
<input
type=
"text"
readonly=
"foobar"
>
<input
type=
"text"
required=
"foobar"
>
<input
type=
"text"
inputmode=
"foobar"
>
...
...
@@ -24,3 +24,424 @@
<!-- type="image" requires alt text -->
<input
type=
"image"
>
<!-- attributes with restrictions based on type -->
<div
id=
"attribute-restriction"
>
<input
type=
"hidden"
accept=
"image/jpeg"
>
<input
type=
"text"
accept=
"image/jpeg"
>
<input
type=
"search"
accept=
"image/jpeg"
>
<input
type=
"url"
accept=
"image/jpeg"
>
<input
type=
"tel"
accept=
"image/jpeg"
>
<input
type=
"email"
accept=
"image/jpeg"
>
<input
type=
"password"
accept=
"image/jpeg"
>
<input
type=
"date"
accept=
"image/jpeg"
>
<input
type=
"month"
accept=
"image/jpeg"
>
<input
type=
"week"
accept=
"image/jpeg"
>
<input
type=
"time"
accept=
"image/jpeg"
>
<input
type=
"datetime-local"
accept=
"image/jpeg"
>
<input
type=
"number"
accept=
"image/jpeg"
>
<input
type=
"range"
accept=
"image/jpeg"
>
<input
type=
"color"
accept=
"image/jpeg"
>
<input
type=
"checkbox"
accept=
"image/jpeg"
>
<input
type=
"radio"
accept=
"image/jpeg"
>
<input
type=
"submit"
accept=
"image/jpeg"
>
<input
type=
"image"
accept=
"image/jpeg"
alt=
"lorem ipsum"
>
<input
type=
"reset"
accept=
"image/jpeg"
>
<input
type=
"hidden"
alt=
"lorem ipsum"
>
<input
type=
"text"
alt=
"lorem ipsum"
>
<input
type=
"search"
alt=
"lorem ipsum"
>
<input
type=
"url"
alt=
"lorem ipsum"
>
<input
type=
"tel"
alt=
"lorem ipsum"
>
<input
type=
"email"
alt=
"lorem ipsum"
>
<input
type=
"password"
alt=
"lorem ipsum"
>
<input
type=
"date"
alt=
"lorem ipsum"
>
<input
type=
"month"
alt=
"lorem ipsum"
>
<input
type=
"week"
alt=
"lorem ipsum"
>
<input
type=
"time"
alt=
"lorem ipsum"
>
<input
type=
"datetime-local"
alt=
"lorem ipsum"
>
<input
type=
"number"
alt=
"lorem ipsum"
>
<input
type=
"range"
alt=
"lorem ipsum"
>
<input
type=
"color"
alt=
"lorem ipsum"
>
<input
type=
"checkbox"
alt=
"lorem ipsum"
>
<input
type=
"radio"
alt=
"lorem ipsum"
>
<input
type=
"file"
alt=
"lorem ipsum"
>
<input
type=
"submit"
alt=
"lorem ipsum"
>
<input
type=
"reset"
alt=
"lorem ipsum"
>
<input
type=
"checkbox"
autocomplete=
"on"
>
<input
type=
"radio"
autocomplete=
"on"
>
<input
type=
"file"
autocomplete=
"on"
>
<input
type=
"submit"
autocomplete=
"on"
>
<input
type=
"image"
autocomplete=
"on"
alt=
"lorem ipsum"
>
<input
type=
"reset"
autocomplete=
"on"
>
<input
type=
"hidden"
capture
>
<input
type=
"text"
capture
>
<input
type=
"search"
capture
>
<input
type=
"url"
capture
>
<input
type=
"tel"
capture
>
<input
type=
"email"
capture
>
<input
type=
"password"
capture
>
<input
type=
"date"
capture
>
<input
type=
"month"
capture
>
<input
type=
"week"
capture
>
<input
type=
"time"
capture
>
<input
type=
"datetime-local"
capture
>
<input
type=
"number"
capture
>
<input
type=
"range"
capture
>
<input
type=
"color"
capture
>
<input
type=
"checkbox"
capture
>
<input
type=
"radio"
capture
>
<input
type=
"submit"
capture
>
<input
type=
"image"
capture
alt=
"lorem ipsum"
>
<input
type=
"reset"
capture
>
<input
type=
"hidden"
checked
>
<input
type=
"text"
checked
>
<input
type=
"search"
checked
>
<input
type=
"url"
checked
>
<input
type=
"tel"
checked
>
<input
type=
"email"
checked
>
<input
type=
"password"
checked
>
<input
type=
"date"
checked
>
<input
type=
"month"
checked
>
<input
type=
"week"
checked
>
<input
type=
"time"
checked
>
<input
type=
"datetime-local"
checked
>
<input
type=
"number"
checked
>
<input
type=
"range"
checked
>
<input
type=
"color"
checked
>
<input
type=
"file"
checked
>
<input
type=
"submit"
checked
>
<input
type=
"image"
checked
alt=
"lorem ipsum"
>
<input
type=
"reset"
checked
>
<input
type=
"hidden"
dirname=
"myname"
>
<input
type=
"url"
dirname=
"myname"
>
<input
type=
"tel"
dirname=
"myname"
>
<input
type=
"email"
dirname=
"myname"
>
<input
type=
"password"
dirname=
"myname"
>
<input
type=
"date"
dirname=
"myname"
>
<input
type=
"month"
dirname=
"myname"
>
<input
type=
"week"
dirname=
"myname"
>
<input
type=
"time"
dirname=
"myname"
>
<input
type=
"datetime-local"
dirname=
"myname"
>
<input
type=
"number"
dirname=
"myname"
>
<input
type=
"range"
dirname=
"myname"
>
<input
type=
"color"
dirname=
"myname"
>
<input
type=
"checkbox"
dirname=
"myname"
>
<input
type=
"radio"
dirname=
"myname"
>
<input
type=
"file"
dirname=
"myname"
>
<input
type=
"submit"
dirname=
"myname"
>
<input
type=
"image"
dirname=
"myname"
alt=
"lorem ipsum"
>
<input
type=
"reset"
dirname=
"myname"
>
<input
type=
"hidden"
formaction=
"/myaction"
>
<input
type=
"text"
formaction=
"/myaction"
>
<input
type=
"search"
formaction=
"/myaction"
>
<input
type=
"url"
formaction=
"/myaction"
>
<input
type=
"tel"
formaction=
"/myaction"
>
<input
type=
"email"
formaction=
"/myaction"
>
<input
type=
"password"
formaction=
"/myaction"
>
<input
type=
"date"
formaction=
"/myaction"
>
<input
type=
"month"
formaction=
"/myaction"
>
<input
type=
"week"
formaction=
"/myaction"
>
<input
type=
"time"
formaction=
"/myaction"
>
<input
type=
"datetime-local"
formaction=
"/myaction"
>
<input
type=
"number"
formaction=
"/myaction"
>
<input
type=
"range"
formaction=
"/myaction"
>
<input
type=
"color"
formaction=
"/myaction"
>
<input
type=
"checkbox"
formaction=
"/myaction"
>
<input
type=
"radio"
formaction=
"/myaction"
>
<input
type=
"file"
formaction=
"/myaction"
>
<input
type=
"reset"
formaction=
"/myaction"
>
<input
type=
"hidden"
formenctype
>
<input
type=
"text"
formenctype
>
<input
type=
"search"
formenctype
>
<input
type=
"url"
formenctype
>
<input
type=
"tel"
formenctype
>
<input
type=
"email"
formenctype
>
<input
type=
"password"
formenctype
>
<input
type=
"date"
formenctype
>
<input
type=
"month"
formenctype
>
<input
type=
"week"
formenctype
>
<input
type=
"time"
formenctype
>
<input
type=
"datetime-local"
formenctype
>
<input
type=
"number"
formenctype
>
<input
type=
"range"
formenctype
>
<input
type=
"color"
formenctype
>
<input
type=
"checkbox"
formenctype
>
<input
type=
"radio"
formenctype
>
<input
type=
"file"
formenctype
>
<input
type=
"reset"
formenctype
>
<input
type=
"hidden"
formmethod=
"post"
>
<input
type=
"text"
formmethod=
"post"
>
<input
type=
"search"
formmethod=
"post"
>
<input
type=
"url"
formmethod=
"post"
>
<input
type=
"tel"
formmethod=
"post"
>
<input
type=
"email"
formmethod=
"post"
>
<input
type=
"password"
formmethod=
"post"
>
<input
type=
"date"
formmethod=
"post"
>
<input
type=
"month"
formmethod=
"post"
>
<input
type=
"week"
formmethod=
"post"
>
<input
type=
"time"
formmethod=
"post"
>
<input
type=
"datetime-local"
formmethod=
"post"
>