Empty → grey · Focus empty → blue · type something invalid → amber / orange + ·
valid → green +
· leave an invalid field → red +
.
Empty → grey · Focus empty → blue glow · type something invalid → red + ! · valid → green + ✓ · fix an invalid field → green. No amber tier.
Honestly, both panes do essentially the same job — they both lean on the browser's own validation for the same states (neutral, focus, and valid/invalid each with and without the focus glow). Two cosmetic differences: Bootstrap keeps its borders and focus glow at a higher non-text contrast (measured 4.5:1), whereas this library trades down toward the 3:1 WCAG minimum for more vivid colours, and it adds an amber / orange “still-typing” warning tier before the red error.
The difference that matters is under the hood. This library ships zero JavaScript — Bootstrap needs a script to drive the live states — and its whole stylesheet is ≈97% smaller than Bootstrap's CSS. Leaning on native CSS pseudo-classes is the whole trick, and also its one limit: it's why an input must carry a placeholder and a constraint to react. That's what keeps the interaction cheap: no runtime JS at all (Bootstrap spends ≈9 ms scripting per form) and about half the combined script-and-layout work, measured in bench/results.json. Both inline their icons as data-URIs, so neither makes a separate icon request.
Primary — drop the placeholder + required requirement. Today all six states are pulled apart with native pseudo-classes alone, which forces two things onto your markup: a placeholder (:placeholder-shown is how we spot an untouched, empty field — it drives the blue “focused & empty” state and guards a fresh field from flashing valid/invalid) and a constraint like required (an input with no constraint is always :valid, so it would sit green from first paint). Both fall out of styling a bare <input> with CSS only. The goal is the same six states with neither attribute — shipping as 2.3.0 if it stays a drop-in CSS change, or 3.0.0 if it needs a small opt-in API (a wrapper or a data- attribute), which would be a breaking change.
Exploring — reuse the state colour for helper / error text. Expose the state colours as text tokens so an error message can echo its input's border. The catch: WCAG asks more contrast of text (4.5:1, 1.4.3) than of borders (3:1, 1.4.11), and the border-tuned light-mode green #00AC0F and orange #EA7200 sit right around 3:1 — so they won't pass as normal-size text. This most likely needs a separate, text-tuned palette rather than reusing the border colour directly, which is why it's still exploratory, not committed to a version.