j3w1 / theme

j3w1 / theme4.0.0

j3w1 / command

  • SPEC Overview
  • SPEC Foundations
  • SPEC Components
  • SPEC Patterns
  • SPEC Tokens
  • SPEC Tools
  • SPEC Workbench
  • SPEC Form builder
  • SPEC Task kit
  • SPEC Recipes
  • SPEC Figma bridge
  • SPEC Report an issue
  • SPEC Implement
  • SPEC For agents
  • SPEC Ports
  • SPEC Releases
  • SPEC Specification
  • DEMO Vue application demo

Text field

Single-line free-text entry, covering every native input type that renders as a line box; search, number and password are variants, not separate components.

stable · light DOM · 4.0.0. Visible native controls retain FormData, labels, constraints, disabled fieldsets and reset. No duplicate form-value mechanism is installed.

Live variants

default

Shown on your profile and in the window title.

✕ Use 2 to 32 characters.

Markup
<j3w1-text-field id="example-text-field-default"><div class="text-field">
  <label class="text-field-label" for="example-text-field-default-tf-name">Display name <span class="text-field-required" aria-hidden="true">*</span><span class="text-field-required sr-only"> required</span></label>
  <div class="text-field-root">
    <input class="text-field-input" id="example-text-field-default-tf-name" type="text" value="j3w1" placeholder="Your name" aria-describedby="example-text-field-default-tf-name-help example-text-field-default-tf-name-message" name="example-text-field-default-tf-name">
    <span class="text-field-loading" aria-hidden="true">⋯</span>
  </div>
  <p class="text-field-help" id="example-text-field-default-tf-name-help">Shown on your profile and in the window title.</p>
  <p class="text-field-message" id="example-text-field-default-tf-name-message">✕ Use 2 to 32 characters.</p>
</div></j3w1-text-field>

password

Twelve characters or more; spaces allowed.

✕ Too short.

Markup
<j3w1-text-field id="example-text-field-password"><div class="text-field">
  <label class="text-field-label" for="example-text-field-password-tf-pass">Passphrase <span class="text-field-required" aria-hidden="true">*</span><span class="text-field-required sr-only"> required</span></label>
  <div class="text-field-root">
    <input class="text-field-input" id="example-text-field-password-tf-pass" type="password" required="" value="correct horse" placeholder="At least 12 characters" aria-describedby="example-text-field-password-tf-pass-help example-text-field-password-tf-pass-message" name="example-text-field-password-tf-pass">
    <button class="text-field-action" type="button" aria-pressed="false" aria-label="Reveal passphrase">reveal</button>
    <span class="text-field-loading" aria-hidden="true">⋯</span>
  </div>
  <p class="text-field-help" id="example-text-field-password-tf-pass-help">Twelve characters or more; spaces allowed.</p>
  <p class="text-field-message" id="example-text-field-password-tf-pass-message">✕ Too short.</p>
</div></j3w1-text-field>

search

Escape clears the query.

✕ No such path.

Markup
<j3w1-text-field id="example-text-field-search"><div class="text-field">
  <label class="text-field-label" for="example-text-field-search-tf-search">Search files <span class="text-field-required" aria-hidden="true">*</span><span class="text-field-required sr-only"> required</span></label>
  <div class="text-field-root">
    <span class="text-field-affix" aria-hidden="true">/</span>
    <input class="text-field-input" id="example-text-field-search-tf-search" type="search" value="site.css" placeholder="Name or path" aria-describedby="example-text-field-search-tf-search-help example-text-field-search-tf-search-message">
    <button class="text-field-action" type="button" aria-label="Clear search">clear</button>
    <span class="text-field-loading" aria-hidden="true">⋯</span>
  </div>
  <p class="text-field-help" id="example-text-field-search-tf-search-help">Escape clears the query.</p>
  <p class="text-field-message" id="example-text-field-search-tf-search-message">✕ No such path.</p>
</div></j3w1-text-field>

number

Up and Down step by one; Shift steps by ten.

✕ Between 0 and 64.

Markup
<j3w1-text-field id="example-text-field-number"><div class="text-field">
  <label class="text-field-label" for="example-text-field-number-tf-gap">Inner gap <span class="text-field-required" aria-hidden="true">*</span><span class="text-field-required sr-only"> required</span></label>
  <div class="text-field-root">
    <input class="text-field-input text-field-input-numeric" id="example-text-field-number-tf-gap" type="number" value="14" min="0" max="64" step="1" placeholder="0" aria-describedby="example-text-field-number-tf-gap-help example-text-field-number-tf-gap-message" name="example-text-field-number-tf-gap">
    <span class="text-field-affix" aria-hidden="true">px</span>
    <span class="text-field-stepper">
      <button class="text-field-action" type="button" aria-label="Increase inner gap">+</button>
      <button class="text-field-action" type="button" aria-label="Decrease inner gap">−</button>
    </span>
    <span class="text-field-loading" aria-hidden="true">⋯</span>
  </div>
  <p class="text-field-help" id="example-text-field-number-tf-gap-help">Up and Down step by one; Shift steps by ten.</p>
  <p class="text-field-message" id="example-text-field-number-tf-gap-message">✕ Between 0 and 64.</p>
</div></j3w1-text-field>

affix

Host only; the path is fixed.

✕ Not a valid host.

Markup
<j3w1-text-field id="example-text-field-affix"><div class="text-field">
  <label class="text-field-label" for="example-text-field-affix-tf-site">Site <span class="text-field-required" aria-hidden="true">*</span><span class="text-field-required sr-only"> required</span></label>
  <div class="text-field-root">
    <span class="text-field-affix" aria-hidden="true">https://</span>
    <input class="text-field-input" id="example-text-field-affix-tf-site" type="text" value="j3w1.github.io" placeholder="host" aria-describedby="example-text-field-affix-tf-site-help example-text-field-affix-tf-site-message" name="example-text-field-affix-tf-site">
    <span class="text-field-affix" aria-hidden="true">/theme/</span>
    <span class="text-field-loading" aria-hidden="true">⋯</span>
  </div>
  <p class="text-field-help" id="example-text-field-affix-tf-site-help">Host only; the path is fixed.</p>
  <p class="text-field-message" id="example-text-field-affix-tf-site-message">✕ Not a valid host.</p>
</div></j3w1-text-field>

Install and register

Use the exact version. If npm publication is pending, install the release tarball from the installation guide.

npm install --save-exact @j3w1/ui@4.0.0
import '@j3w1/ui/tokens.css';
import '@j3w1/ui/styles/text-field.css';
import '@j3w1/ui/register/text-field';

Insert the maintained markup above after loading these imports. Its native children provide accessible names and form behavior; the empty custom tag alone does not create a control.

Vue SFC, React, Astro and plain HTML integration →

Copy the complete implementation

npx --package=@j3w1/ui@4.0.0 j3w1-ui copy text-field --out ./vendor/j3w1/text-field

The CLI verifies every file before writing and refuses overwrites. Serve the output over HTTP and open index.html. Keep its modules, CSS, tokens and licence notices together.

Public API

attributes

NameType / signatureMeaning
disabledCustomEventDisable the native controls owned by this instance.
loadingCustomEventMark the primary control busy and prevent duplicate activation.
valueCustomEventForwards value to the primary native control.
requiredCustomEventForwards required to the primary native control.
readonlyCustomEventForwards readonly to the primary native control.
checkedCustomEventForwards checked to the primary native control.

properties

NameType / signatureMeaning
disabledbooleanDelegates disabled state to native children.
namestringNative control name; application form keys remain explicit.
valuestringPrimary native value; assignment does not fabricate user events.
checkedbooleanNative checkbox state.
requiredbooleanNative required constraint.
readOnlybooleanNative readonly property.
formHTMLFormElement | nullOwning native form. Read only.

methods

NameType / signatureMeaning
refresh(): voidReconnect behavior after replacing native child structure.
focus(options?: FocusOptions): voidFocus the first usable native control.
checkValidity(): booleanCheck owned native constraints.
reportValidity(): booleanReport the first invalid owned control.
clear(): voidClear an editable primary input and emit native input/change.
stepBy(amount: number): voidStep a number input by the supplied number of native steps.

events

NameType / signatureMeaning
j3w1-changeCustomEventNative change from an owned control, alongside the original native event.

Dependencies and verification

Registered components: none. Style dependencies: none.

Package presence establishes an available implementation. Actual passes depend on the tested artifact and environment. Read specification execution evidence; read packed-consumer evidence; inspect the complete state matrix.

Full implementation manifest, API and token dependency closure

Canonical specification

Text field text-field

  • Family: Basic forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <input> with <label> — APG pattern
  • specified
  • demonstrated
  • test implemented

Single-line free-text entry, covering every native input type that renders as a line box; search, number and password are variants, not separate components.

Report an issue with this component

Open component workbench

View source and copy recipe · Download standalone example

Tokens

Focus a role to inspect its values; follow its link for persistent usage and source details.

PartRoleValueUse
root.bgcolor.surface.inputapproveduse#000000Form-control fill.
root.bordercolor.border.controlapproveduse#c81a1aD-041 owner correction: red control and floating-frame borders, distinct from rose text.
root.bg-hovercolor.interaction.hover.bgapproveduse#1c1010D-041 interaction.hover.bg: color.primitive.modern.hover.
root.border-focuscolor.border.activeobserveduse#e53935Active or focused control border.
root.ringcolor.interaction.focus.ringobserveduse#e539351px dashed focus ring on controls and rows.
root.ring-invalidcolor.interaction.focus.ring-containerobserveduse#ffa2a7Focus colour for containers and explicitly mapped filled controls (D-015); component rules determine ring geometry.
root.border-invalidcolor.status.danger.borderobserveduse#e53935Danger border, 2px on invalid inputs.
root.border-disabledcolor.border.disabledapproveduse#482b2bD-041 border.disabled: color.primitive.modern.divider.
root.bg-disabledcolor.interaction.disabled.bgapproveduse#0d0707D-041 interaction.disabled.bg: color.primitive.modern.panel.
root.border-readonlycolor.border.dividerapproveduse#482b2bD-041 border.divider: color.primitive.modern.divider.
input.textcolor.text.defaultapproveduse#e99499D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
input.text-disabledcolor.text.disabledapproveduse#a3676bD-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
input.placeholdercolor.text.placeholderapproveduse#bd787dD-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
input.caretcolor.code.caretapproveduse#ffa2a7D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
input.selection-bgcolor.interaction.text-selection.bgobserveduse#420f0cD-041 subdued burgundy selection keeps rose text readable in hosts retaining its foreground.
input.selection-textcolor.interaction.text-selection.textobserveduse#f4eeee::selection text.
label.textcolor.text.brightapproveduse#ffa2a7D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
label.required-markcolor.status.danger.textobserveduse#f07178D-041 readable error text on neutral surfaces and native warning tints.
help.textcolor.text.mutedapproveduse#d4868bD-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
message.textcolor.status.danger.textobserveduse#f07178D-041 readable error text on neutral surfaces and native warning tints.
affix.textcolor.text.mutedapproveduse#d4868bD-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
affix.bordercolor.border.dividerapproveduse#482b2bD-041 border.divider: color.primitive.modern.divider.
action.textcolor.action.tertiary.textapproveduse#e99499D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
action.bg-hovercolor.action.tertiary.hover-bgobserveduse#1c0a09Ghost and icon button hover.
loading.glyphcolor.text.mutedapproveduse#d4868bD-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.

State matrix

Every declared state and combination, statically rendered; the default cell is live. Sizes: compact, comfortable (switch with the density control above).

StateTextPassword with revealSearch with clearNumber with stepperWith prefix and suffix
default

Shown on your profile and in the window title.

✕ Use 2 to 32 characters.

Twelve characters or more; spaces allowed.

✕ Too short.

Escape clears the query.

✕ No such path.

Up and Down step by one; Shift steps by ten.

✕ Between 0 and 64.

Host only; the path is fixed.

✕ Not a valid host.

hover
focus-visible
placeholder-shown
filled
required
invalid
invalid+focus-visible
invalid+hover
disabled
disabled+filled
read-only
read-only+focus-visible
loading

Purpose

Single-line free-text entry for every native type that renders as a line box (text, password, search, number, email, url, tel). Date and time inputs are the date-picker and time-picker components.

Anatomy

Parts as listed in the anatomy.

States

StateVisualNon-colour channel
default1px color.border.control on color.surface.input; text color.text.default—
hoverbackground → color.interaction.hover.bg; border unchangedcursor: text
focus-visibleborder → color.border.active; 1px dashed color.interaction.focus.ring ring at −2pxthe ring
placeholder-shownplaceholder in color.text.placeholder, italicitalic
filledas default with a value—
required* after the label in color.status.danger.text plus visually hidden “required”required attribute; the mark
invalid2px color.status.danger.border; message with the ✕ glyphborder 1 → 2px; glyph; aria-invalid
invalid+focus-visiblethe 2px danger border plus a 1px dashed color.interaction.focus.ring-container ring at −4px (the control form recoloured, never the 2px container form)double boundary
invalid+hoveras invalid with the hover backgroundcursor
disabledtext color.text.disabled, border color.border.disabled, background color.interaction.disabled.bg; no hover; label and help keep their coloursdisabled; cursor: not-allowed
disabled+filledas disabled with a valuedisabled
read-onlyno box: 1px dotted color.border.divider bottom edge on color.surface.canvas; text color.text.default; focusable and selectablereadonly; dotted edge
read-only+focus-visiblethe dotted edge unchanged, plus the dashed ring at −2pxthe ring
loadingsize unchanged; static ⋯ in color.text.muted after the input, before any trailing action; still editableglyph; aria-busy

Precedence: disabled > loading > invalid > hover; focus-visible is always drawn.

Keyboard

As in the key table; the label is not a stop, and clear or reveal precede the stepper buttons.

Accessibility

The clear button is type="button" with aria-label="Clear <label>"; the reveal button toggles type between password and text and its own aria-pressed. aria-invalid is never set on first paint. The message is announced on submit through the form’s live region, not on every keystroke. Text meets 4.5:1 and borders and rings 3:1; disabled text is exempt (house floor 3:1). The box is at least 24×24 CSS pixels in compact.

Portability

Border, background and outline express everything; the only pseudo-element is the required mark. Toolkits without dashed outlines draw a solid 1px ring in the same colour; toolkits without a read-only style show read-only as default text. Both record the deviation.

Non-examples

Rounded corners. A floating or animated label. An underline-only field. A glow instead of the dashed ring. Red placeholder text. Disabling by opacity. Colour alone for the invalid state. A hover that changes the text colour.

Contrast report

20 declared pairs measured on resolved sRGB values with the WCAG 2.x formula; 0 waived (decorative only), 0 failing. A pass is a design target for the named role, not an application-wide conformance claim.

PairStateKindForegroundBackgroundRatioMinResult
text-field default textdefaulttextcolor.text.default #e99499color.surface.input #0000009.164.5pass
text-field default borderdefaultuicolor.border.control #c81a1acolor.surface.input #0000003.623pass
text-field hover texthovertextcolor.text.default #e99499color.interaction.hover.bg #1c10108.104.5pass
text-field hover borderhoveruicolor.border.control #c81a1acolor.interaction.hover.bg #1c10103.203pass
text-field focus-visible textfocus-visibletextcolor.text.default #e99499color.surface.input #0000009.164.5pass
text-field focus-visible borderfocus-visibleuicolor.border.active #e53935color.surface.input #0000004.973pass
text-field focus-visible outlinefocus-visibleuicolor.interaction.focus.ring #e53935color.surface.input #0000004.973pass
text-field placeholder-shown textplaceholder-showntextcolor.text.placeholder #bd787dcolor.surface.input #0000006.154.5pass
text-field placeholder-shown borderplaceholder-shownuicolor.border.control #c81a1acolor.surface.input #0000003.623pass
text-field invalid textinvalidtextcolor.text.default #e99499color.surface.input #0000009.164.5pass
text-field invalid borderinvaliduicolor.status.danger.border #e53935color.surface.input #0000004.973pass
text-field invalid+focus-visible textinvalid+focus-visibletextcolor.text.default #e99499color.surface.input #0000009.164.5pass
text-field invalid+focus-visible borderinvalid+focus-visibleuicolor.status.danger.border #e53935color.surface.input #0000004.973pass
text-field invalid+focus-visible outlineinvalid+focus-visibleuicolor.interaction.focus.ring-container #ffa2a7color.surface.input #00000010.983pass
text-field read-only textread-onlytextcolor.text.default #e99499color.surface.canvas #0000009.164.5pass
validation message on the panel surface—textcolor.status.danger.text #f07178color.surface.default #0d07076.984.5pass
help text on the panel surface—textcolor.text.muted #d4868bcolor.surface.default #0d07077.224.5pass
disabled text (exempt; house floor 3:1)disableduicolor.text.disabled #a3676bcolor.interaction.disabled.bg #0d07074.483pass
disabled border (exempt)disableduicolor.border.disabled #482b2bcolor.interaction.disabled.bg #0d07071.581pass
read-only bottom edge (decorative; the field has no box)read-onlyuicolor.border.divider #482b2bcolor.surface.canvas #0000001.661pass

Keys

KeyAction
Tab / Shift+TabMoves focus in and out; affix actions (clear, reveal, stepper) are separate tab stops after the input.
EscapeClears the value in the search variant when it is non-empty; otherwise nothing.
EnterSubmits the owning form (native).
Up / DownNumber variant steps by the step attribute; Shift multiplies by ten.

For agents

Component JSON ·Implementation brief ·Build a task kit ·

Related: textarea select combobox search-field number-field field

Stress fixtures: FX-LONG FX-320 FX-360 FX-ZOOM-200 FX-I18N FX-RTL FX-RM FX-HC FX-TOUCH FX-DENSITY FX-STATE-MATRIX