Validated Inputs

Input components with built-in validation. The client-side validators below run entirely in the browser (no round-trip); the older components further down call server endpoints on blur.

Client-side validators (live)

Wired declaratively with data-validate="<name>" (see static/js/validation.js). These validate on every keystroke and on blur, with three behaviors:

  • Partial: a good-so-far but incomplete value stays neutral while typing, and is only rejected when you leave the field.
  • Eager fail: the instant a value can never become valid (e.g. a W in a Roman numeral, a letter in an integer), it fails immediately — no need to blur.
  • Normalize on blur: valid values are rewritten to canonical form when you leave the field.

Whole numbers only. Type a letter to see an eager fail; "-" alone is incomplete.

Integers, decimals, and scientific notation. "1." and "1e" are partial.

Normalizes to XXX-XXX-XXXX on blur. Fewer than 10 digits is partial; a letter fails eagerly.

Binary (KiB/MiB/GiB) and decimal (KB/MB/GB) units; a bare number is bytes. "10 G" is a partial unit.

Arabic 1-3999 or Roman letters, normalized to canonical uppercase. "W" or "IIII" fails eagerly.

Deliberately permissive: exactly one @ with text on both sides — no character or TLD rules. A second @ fails eagerly.

Try these

  • Integer: type 12a → fails immediately; - → stays neutral, then invalid on blur.
  • Storage: 10gib10 GiB; 10241024 B; 10 X → invalid unit.
  • Roman: 2024MMXXIV; viVI; W → immediate fail.

Date Picker

Uses the browser's native date picker. Accepts ISO (YYYY-MM-DD) or US (MM/DD/YYYY) format.

Accepts YYYY-MM-DD or MM/DD/YYYY format

Try entering an invalid date like 2024-02-30 to see validation.

Time Input

Accepts both 24-hour (14:30) and 12-hour (2:30 PM) formats. Invalid mixed formats like "13:22 PM" are rejected.

Accepts 24-hour (14:30) or 12-hour (2:30 PM) format

Test Cases

  • 14:30 - Valid 24-hour format
  • 2:30 PM - Valid 12-hour format
  • 13:22 PM - Invalid (can't use PM with hour > 12)
  • 25:00 - Invalid (hour out of range)

DateTime Picker

Combines date and time inputs. Both are validated independently.

The combined ISO datetime is stored in a hidden field for form submission.

Number Input

Accepts integers, decimals, and scientific notation. The input uses a text field for unlimited precision.

Valid Formats

  • 123 - Integer
  • -456 - Negative integer
  • 123.456 - Decimal
  • .5 - Leading decimal
  • 5. - Trailing decimal
  • 1e10 - Scientific notation
  • 1.5e-3 - Scientific with decimal

Phone Number

Accepts any common phone format. Strips non-digit characters and normalizes to XXX-XXX-XXXX. A leading US country code (1) is dropped.

Accepts 10 digits in any format; 11 digits starting with 1 also works.

Test Cases

  • (303) 555-1234303-555-1234
  • 303.555.1234303-555-1234
  • 1-800-555-1212800-555-1212 (country code dropped)
  • 555-1234 - Invalid (too few digits)

Email Address

Accepts any string with exactly one @ and non-empty text on both sides. Normalizes by trimming whitespace (case preserved).

Must contain exactly one @ with text on both sides.

Test Cases

  • name@example.com - Valid
  • a@b a@b (trimmed)
  • nope - Invalid (no @)
  • a@b@c - Invalid (multiple @)

Roman Numeral

Accepts an Arabic integer (1-9999) or a Roman numeral (case-insensitive) and normalizes to a canonical uppercase Roman numeral. Non-canonical input like IIII is accepted and re-emitted as IV.

Accepts a number 1-9999 or a Roman numeral.

Test Cases

  • 2024MMXXIV
  • iiiiIV (canonicalized)
  • xivXIV
  • 0 - Invalid (Roman has no zero)
  • 10000 - Invalid (out of range)

How It Works

Validation Flow

  1. User enters a value and blurs (leaves) the input
  2. HTMX sends a POST request to /validate/{type}
  3. Server validates and returns JSON: {"valid": true, "normalized": "..."} or {"valid": false, "error": "..."}
  4. JavaScript updates the input state (green/red border) and shows any error message
  5. If valid, the input value is updated to the normalized form

Server Endpoints

  • POST /validate/date - Validates date strings
  • POST /validate/time - Validates time strings
  • POST /validate/datetime - Validates datetime strings
  • POST /validate/number - Validates number strings
  • POST /validate/phone - Validates & normalizes phone numbers
  • POST /validate/email - Validates email addresses
  • POST /validate/roman - Validates & canonicalizes Roman numerals

All endpoints accept form data with a value field and return JSON.