Skip to main content
Problem 39

Build a PIN Code Input

EASYBUILD
DOM & Events+3
Brief

Build a 4-digit PIN entry component inside the existing app container. It must behave like a real PIN pad: each box accepts exactly one digit, focus moves automatically between boxes as the user types and deletes, and the component signals when all four digits have been filled.

All DOM construction and event wiring must be done in main.js.

Requirements
  • Render 4 single-character text inputs with data-testid values pin-digit-0, pin-digit-1, pin-digit-2, and pin-digit-3 inside the app container.
  • Each input accepts only digit characters (0–9). Any non-digit keypress must be ignored and must not populate the input or advance focus.
  • When a digit is entered, focus automatically moves to the next input. If the last input is filled, focus stays on it.
  • When Backspace is pressed on an empty input, focus moves back to the previous input. If the first input is already focused, Backspace has no focus side-effect.
  • When all 4 inputs contain a digit, dispatch a custom complete event on the app container with detail: { pin: "XXXX" } where XXXX is the 4-digit string.
  • Render a button with data-testid="clear-btn" that clears all inputs and returns focus to the first input. The complete event may fire again after clearing if all 4 digits are re-entered.
Examples
Example 1
Input
User types '1', '2', '3', '4'
Output
complete event fires with detail.pin = '1234'
Note

Each digit entry advances focus to the next box. After the 4th digit, the complete event fires.

Example 2
Input
User types '1', then 'a', then '2'
Output
Inputs show '1', '', '2', '' — focus is on index 2
Note

'a' is not a digit — it is ignored. Focus does not advance on a rejected keypress.

Example 3
Input
User types '1', then presses Backspace twice
Output
First Backspace clears '1' in box 0 (stays on box 0). Second Backspace on an already-empty box 0 has no effect.
Note

Backspace clears the current box's content. If the box is already empty, focus moves to the previous box.

Constraints
  • Use only vanilla JavaScript — no React, Vue, or other frameworks.
  • The complete event must be dispatched on the element with data-testid="app", not on any individual input.
Judge checks
  • browser environment
  • browser-eval runner
  • 8000ms judge budget
Follow-up

This component manages 4 independent DOM nodes. How would you structure this if the number of digits was configurable via a `data-length` attribute on the container?

Hints
Console output appears after the preview logs something.