NS Design System
v3.0.0 · 257 tokens

18Input

Single-line text entry. Hairline border, 40px target, focus ring via :focus-visible. The mono variant is for data — org IDs, codes, keys — Principle 2 applied to input.

Use it for

  • Free text, email, password, search
  • mono for anything that is a value rather than a sentence

Not for

  • Choosing from a known list — Select
  • Multi-line prose — Textarea

Types

One class, every HTML type — the type attribute buys the right keyboard, autofill and native pickers for free.

markup
<div style="display:grid;gap:var(--space-3);max-inline-size:20rem;inline-size:100%">
  <input class="ns-input" type="text" placeholder="Text — a sentence or a name">
  <input class="ns-input" type="email" placeholder="you@example.com" autocomplete="email">
  <input class="ns-input" type="password" value="hunter2hunter" autocomplete="current-password">
  <input class="ns-input" type="number" placeholder="Number — 42" min="0">
  <input class="ns-input" type="date">
  <input class="ns-input" type="url" placeholder="https://…">
</div>

States

Hover brightens the hairline; focus draws the 2px brand ring (click into one); active/filled is just the value present — no floating labels. Disabled leaves the tab order; readonly stays readable and copyable.

markup
<div style="display:grid;gap:var(--space-3);max-inline-size:20rem;inline-size:100%">
  <input class="ns-input" placeholder="Rest — hover me, then click in">
  <input class="ns-input" value="Filled — the quiet state">
  <input class="ns-input" value="Read-only value" readonly>
  <input class="ns-input" value="Disabled" disabled>
</div>

Validation

aria-invalid drives the red hairline; the Field's error names what is wrong AND what to do, and role="alert" announces it. Never color alone, never just "invalid".

Valid

markup
<div class="ns-field" style="max-inline-size:20rem">
  <label class="ns-field__label" for="in-v1">Email address</label>
  <input class="ns-input" id="in-v1" type="email" value="swarnil@gmail" aria-invalid="true" aria-describedby="in-v1-e">
  <p class="ns-field__error" id="in-v1-e" role="alert">That address is missing its domain — like .com</p>
</div>
<div class="ns-field" style="max-inline-size:20rem">
  <label class="ns-field__label" for="in-v2">Org ID</label>
  <input class="ns-input ns-input--mono" id="in-v2" value="00D5g000004abcEAA" aria-describedby="in-v2-h">
  <p class="ns-field__help" id="in-v2-h"><span class="ns-status ns-status--success">Valid</span></p>
</div>

Mono — for data

Org IDs, codes, keys — a value, not a sentence (Principle 2).

markup
<input class="ns-input ns-input--mono" value="00D5g000004abcEAA" style="max-inline-size:16rem">

Icon and shortcut hint

markup
<span class="ns-input-wrap" style="max-inline-size:20rem">
  <i class="ph ph-magnifying-glass ns-input-wrap__icon" aria-hidden="true"></i>
  <input class="ns-input ns-input--has-icon ns-input--has-hint" type="search" placeholder="Search courses…">
  <kbd class="ns-input-wrap__hint" aria-hidden="true">⌘K</kbd>
</span>

Accessibility contract

  • Always inside a Field (or with an explicit label) — placeholder is never a label
  • The ⌘K hint is aria-hidden: a keyboard user tabbing in does not need it read out