Text Field

Free

Single- and multi-line inputs with validation states, icons, addons, hints and character counting.

</>sv-input-field inputformtext
import { SvInputFieldComponent } from '@styloviz/input-field';

Demo & usage

Basic usage

Live, interactive instance.

More examples

Validation state

Drive the field with state + errorMessage for inline validation.

example.htmlAngular
<sv-input-field
  label="Username"
  state="error"
  errorMessage="That username is taken."
  [(value)]="username" />

Addons & icons

Leading icon, trailing addon and a character counter.

example.htmlAngular
<sv-input-field
  label="Website"
  leadingIcon="link"
  trailingAddon=".com"
  [maxLength]="40"
  [(value)]="site" />

Multiline

example.htmlAngular
<sv-input-field label="Notes" [multiline]="true" [maxLength]="280" [(value)]="notes" />

Native constraints & autofill

Pass-through native attributes for real validation and better mobile keyboards. pattern, minLength, min/max/step feed the built-in Validator.

example.htmlAngular
<sv-input-field
  label="One-time code"
  inputMode="numeric"
  pattern="\d{6}"
  autocomplete="one-time-code"
  [maxLength]="6"
  [(value)]="code" />

Reactive forms (CVA + Validator)

Works with formControlName; required/minLength/pattern surface as control errors and disable() disables the native control.

example.htmlAngular
<sv-input-field
  formControlName="email"
  label="Email"
  type="email"
  [required]="true"
  autocomplete="email" />

When to use

  • Collecting a single line of free-form text, email, password or number.
  • You need built-in label, hint, validation and counter wiring instead of a bare <input>.
  • Switch to `multiline` for short paragraphs; use the Rich Text Editor for formatted content.

Async states

  • loading

Inputs

NameTypeDefaultDescription
valuestring (two-way)''Current value. Use `[(value)]` for signal two-way binding.
typeInputType'text'Input type.
multilinebooleanfalseRenders a `<textarea>` instead of `<input>`.
optionsInputOption[][]When set, renders a `<select>` element. Use `type` is ignored when options are provided.
labelstring''Label text shown above the input.
requiredbooleanfalseMarks the label with a red asterisk.
optionalTagbooleanfalseOptional label (replaces asterisk with a soft "(optional)" tag).
placeholderstring''Placeholder text.
hintstring''Helper text shown below the input (hidden when either error is set).
errorMessagestring''Error message — switches state to `error` automatically when non-empty.
serverErrorstring | { readonly message: string } | nullnullA validation failure reported by the **server** — the 422 that comes back after submit, not something the client could have known. It is a separate input from `errorMessage` because it has a different lifetime, not because it needs a second way to show a string. A server error is a statement about *the value that was submitted*: the moment the user edits the field it stops being true, and this input expires itself rather than sitting there telling someone their new email is already taken. `errorMessage` has no such expiry — it is the host's to clear. While live it outranks `errorMessage`: it is the more specific fact, and it is the one the user has not seen yet. Typed structurally rather than as `SvDataError` so this stays dependency free — an `SvDataError` satisfies it unchanged.
successMessagestring''Success message — shown below when state is `success`.
variantInputVariant'default'Visual style.
sizeInputSize'md'Size.
stateInputState'default'Explicit validation state override. Automatically set to `'error'` when `errorMessage` is non-empty.
leadingIconstring''Icon-library NAME for the leading (left) icon — e.g. `'mail'`. BREAKING (icon sweep): was `leadingIconPath`, a raw SVG `d` string. Every showcase call site wrote it as a STATIC attribute, which Angular silently ignores once the input is renamed — so the old name cannot be left behind as a deprecated alias without the two quietly disagreeing.
trailingIconstring''Icon-library NAME for the trailing (right) icon — e.g. `'calendar'`. Was `trailingIconPath`, a raw SVG `d` string.
leadingAddonstring''Short text prepended inside the input (e.g. `'https://'`, `'$'`). Ignored when `leadingIcon` is set.
trailingAddonstring''Short text appended inside the input (e.g. `'.com'`, `'USD'`). Ignored when `trailingIcon` is set.
maxLengthnumber0Maximum character count shown as a counter below the input. Set to 0 to disable.
disabledbooleanfalseDisable the input.
readonlybooleanfalseRead-only mode.
loadingbooleanfalseShow a loading spinner in the trailing position.
inputIdstring''id forwarded to the native input — required for external `<label for>`.
ariaLabelstring''Accessible name for the control, for the case where there is no visible label. A PLACEHOLDER IS NOT AN ACCESSIBLE NAME. It disappears the moment somebody types, it is not reliably announced, and until this input existed a label-less field here rendered an `<input>` with **no name at all** — no `<label>`, no `aria-label`. That is a WCAG 4.1.2 failure, and label-less fields are an ordinary pattern: a search box, an inline sign-up row, a filter above a table. Ignored when `label` is set. `aria-label` overrides a visible `<label>` in the accessibility tree, so letting both apply would let a stale name silently shadow the one on screen.
inputNamestring''name attribute for the native input.
customClassstring''Additional CSS classes on the root wrapper.
autocompletestring''`autocomplete` token (e.g. 'email', 'name', 'current-password', 'one-time-code'). Defaults to 'current-password' for password type, otherwise the browser default. Applied to the `<input>`, the `<textarea>` (`multiline`, e.g. 'street-address') and the `<select>` (`options`, e.g. 'country', 'bday-month') alike.
inputModeInputMode | ''''Virtual-keyboard hint for mobile (e.g. 'numeric', 'email', 'tel').
patternstring''Native validation regex (without anchors — anchored automatically).
minLengthnumber0Minimum length used by the built-in Validator and native `minlength`.
minstring | number | nullnullNative `min` for number/date/range types.
maxstring | number | nullnullNative `max` for number/date/range types.
stepstring | number | nullnullNative `step` for number/date/range types.
spellcheckboolean | nullnullNative spellcheck toggle. null = browser default.
autofocusbooleanfalseAutofocus the control on render.

Outputs

EventPayload typeDescription
focusedFocusEventEmits when the input gains focus.
blurredFocusEventEmits when the input loses focus.
submittedstringEmits when Enter is pressed.
valueChangestringEmits the new `value` whenever it changes — the output half of `[(value)]`.

<sv-input-field-pro>

Also in this family — SvInputFieldProComponent from @styloviz-pro/input-field.

Async states

  • loading

Inputs

NameTypeDefaultDescription
valuestring (two-way)''Current value. Use `[(value)]` for signal two-way binding.
typeInputType'text'Input type.
multilinebooleanfalseRenders a `<textarea>` instead of `<input>`.
optionsInputOption[][]When set, renders a `<select>` element. Use `type` is ignored when options are provided.
labelstring''Label text shown above the input.
requiredbooleanfalseMarks the label with a red asterisk.
optionalTagbooleanfalseOptional label (replaces asterisk with a soft "(optional)" tag).
placeholderstring''Placeholder text.
hintstring''Helper text shown below the input (hidden when either error is set).
errorMessagestring''Error message — switches state to `error` automatically when non-empty.
serverErrorstring | { readonly message: string } | nullnullA validation failure reported by the **server** — the 422 that comes back after submit, not something the client could have known. It is a separate input from `errorMessage` because it has a different lifetime, not because it needs a second way to show a string. A server error is a statement about *the value that was submitted*: the moment the user edits the field it stops being true, and this input expires itself rather than sitting there telling someone their new email is already taken. `errorMessage` has no such expiry — it is the host's to clear. While live it outranks `errorMessage`: it is the more specific fact, and it is the one the user has not seen yet. Typed structurally rather than as `SvDataError` so this stays dependency free — an `SvDataError` satisfies it unchanged.
successMessagestring''Success message — shown below when state is `success`.
variantInputVariant'default'Visual style.
sizeInputSize'md'Size.
stateInputState'default'Explicit validation state override. Automatically set to `'error'` when `errorMessage` is non-empty.
leadingIconstring''Icon-library NAME for the leading (left) icon — e.g. `'mail'`. BREAKING (icon sweep): was `leadingIconPath`, a raw SVG `d` string. Every showcase call site wrote it as a STATIC attribute, which Angular silently ignores once the input is renamed — so the old name cannot be left behind as a deprecated alias without the two quietly disagreeing.
trailingIconstring''Icon-library NAME for the trailing (right) icon — e.g. `'calendar'`. Was `trailingIconPath`, a raw SVG `d` string.
leadingAddonstring''Short text prepended inside the input (e.g. `'https://'`, `'$'`). Ignored when `leadingIcon` is set.
trailingAddonstring''Short text appended inside the input (e.g. `'.com'`, `'USD'`). Ignored when `trailingIcon` is set.
maxLengthnumber0Maximum character count shown as a counter below the input. Set to 0 to disable.
disabledbooleanfalseDisable the input.
readonlybooleanfalseRead-only mode.
loadingbooleanfalseShow a loading spinner in the trailing position.
inputIdstring''id forwarded to the native input — required for external `<label for>`.
ariaLabelstring''Accessible name for the control, for the case where there is no visible label. A PLACEHOLDER IS NOT AN ACCESSIBLE NAME. It disappears the moment somebody types, it is not reliably announced, and until this input existed a label-less field here rendered an `<input>` with **no name at all** — no `<label>`, no `aria-label`. That is a WCAG 4.1.2 failure, and label-less fields are an ordinary pattern: a search box, an inline sign-up row, a filter above a table. Ignored when `label` is set. `aria-label` overrides a visible `<label>` in the accessibility tree, so letting both apply would let a stale name silently shadow the one on screen.
inputNamestring''name attribute for the native input.
customClassstring''Additional CSS classes on the root wrapper.
autocompletestring''`autocomplete` token (e.g. 'email', 'name', 'current-password', 'one-time-code'). Defaults to 'current-password' for password type, otherwise the browser default. Applied to the `<input>`, the `<textarea>` (`multiline`, e.g. 'street-address') and the `<select>` (`options`, e.g. 'country', 'bday-month') alike.
inputModeInputMode | ''''Virtual-keyboard hint for mobile (e.g. 'numeric', 'email', 'tel').
patternstring''Native validation regex (without anchors — anchored automatically).
minLengthnumber0Minimum length used by the built-in Validator and native `minlength`.
minstring | number | nullnullNative `min` for number/date/range types.
maxstring | number | nullnullNative `max` for number/date/range types.
stepstring | number | nullnullNative `step` for number/date/range types.
spellcheckboolean | nullnullNative spellcheck toggle. null = browser default.
autofocusbooleanfalseAutofocus the control on render.

Outputs

EventPayload typeDescription
focusedFocusEventEmits when the input gains focus.
blurredFocusEventEmits when the input loses focus.
submittedstringEmits when Enter is pressed.
valueChangestringEmits the new `value` whenever it changes — the output half of `[(value)]`.

Customization & theming

  • Set `type` (text, email, password, number…) or `multiline` for a textarea; pick a `variant` (default, filled, flushed, floating) and `size`.
  • Drive validation with `state`, `errorMessage` and `successMessage`, or let the built-in Validator enforce `required`, `minLength`, `maxLength` and `pattern`.
  • Tune native behaviour with `autocomplete`, `inputMode`, `min` / `max` / `step`, `spellcheck` and `autofocus`.
  • Add `leadingIcon` / `trailingIcon`, `leadingAddon` / `trailingAddon` and `maxLength` counter; listen to `focused`, `blurred` and `submitted` (Enter).

Best practices

  • Do: Always set a `label`; use `hint` for guidance and `errorMessage` for the failure reason.
  • Do: Pick the right `type` plus `inputMode` / `autocomplete` so mobile keyboards and autofill adapt.
  • Don't: Don't rely on `placeholder` as the label — it disappears once the user types.
  • Tip: Bind `state` to your form-control status so the error styling stays in sync.

Accessibility

  • A stable id is generated automatically, so the `<label for>` association and `aria-describedby` work even when no `inputId` is supplied.
  • Hint, error and success text are linked via `aria-describedby`; `aria-invalid` and `aria-required` reflect state, and errors use `role="alert"`.
  • The password show/hide toggle is keyboard reachable with `aria-pressed`; the character counter announces politely via `aria-live`.
  • Supports `disabled` and `readonly` with correct semantics — programmatic `formControl.disable()` disables the native control too.

Feedback on Text Field

Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.

Loads giscus.app and GitHub — nothing is fetched until you click.