Input OTP
A one-time code: one native text input in a .canon-otp box, its maxlength the code's length. canon.js draws a cell per character and keeps the input over them, so typing, pasting, the browser filling a code it received (autocomplete="one-time-code") and the label all work as on any input. Without JavaScript it is one plain field. Specification: docs/components/input-otp.md
Size
data-size on the field or a container: cells are square at a text input's height.
Groups
data-groups on the box: the group sizes, adding up to maxlength, with a line between groups. Without it, the cells are one group. The value is the characters alone, with no separators.
Characters
inputmode="numeric" keeps digits only and brings up a number pad on phones. Without it, letters and digits are kept. Anything else typed is ignored, and a pasted code is cleaned (123-456 becomes 123456). Add pattern for the browser's own check on submit.
Placeholder
Each empty cell shows its character of the input's placeholder.
States
Text Input's states. The cell at the caret shows focus, with a blinking caret while it's empty. disabled on the input; an error with aria-invalid="true" and a danger message.
Edge cases
Right-to-left
Codes read left to right in every language: the cells keep their order.