Text Field
FreeSingle- and multi-line inputs with validation states, icons, addons, hints and character counting.
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.
<sv-input-field label="Username" state="error" errorMessage="That username is taken." [(value)]="username" />
Addons & icons
Leading icon, trailing addon and a character counter.
<sv-input-field label="Website" leadingIcon="link" trailingAddon=".com" [maxLength]="40" [(value)]="site" />
Multiline
<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.
<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.
<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
| Name | Type | Default | Description |
|---|---|---|---|
| value | string (two-way) | '' | Current value. Use `[(value)]` for signal two-way binding. |
| type | InputType | 'text' | Input type. |
| multiline | boolean | false | Renders a `<textarea>` instead of `<input>`. |
| options | InputOption[] | [] | When set, renders a `<select>` element. Use `type` is ignored when options are provided. |
| label | string | '' | Label text shown above the input. |
| required | boolean | false | Marks the label with a red asterisk. |
| optionalTag | boolean | false | Optional label (replaces asterisk with a soft "(optional)" tag). |
| placeholder | string | '' | Placeholder text. |
| hint | string | '' | Helper text shown below the input (hidden when either error is set). |
| errorMessage | string | '' | Error message — switches state to `error` automatically when non-empty. |
| serverError | string | { readonly message: string } | null | null | A 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. |
| successMessage | string | '' | Success message — shown below when state is `success`. |
| variant | InputVariant | 'default' | Visual style. |
| size | InputSize | 'md' | Size. |
| state | InputState | 'default' | Explicit validation state override. Automatically set to `'error'` when `errorMessage` is non-empty. |
| leadingIcon | string | '' | 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. |
| trailingIcon | string | '' | Icon-library NAME for the trailing (right) icon — e.g. `'calendar'`. Was `trailingIconPath`, a raw SVG `d` string. |
| leadingAddon | string | '' | Short text prepended inside the input (e.g. `'https://'`, `'$'`). Ignored when `leadingIcon` is set. |
| trailingAddon | string | '' | Short text appended inside the input (e.g. `'.com'`, `'USD'`). Ignored when `trailingIcon` is set. |
| maxLength | number | 0 | Maximum character count shown as a counter below the input. Set to 0 to disable. |
| disabled | boolean | false | Disable the input. |
| readonly | boolean | false | Read-only mode. |
| loading | boolean | false | Show a loading spinner in the trailing position. |
| inputId | string | '' | id forwarded to the native input — required for external `<label for>`. |
| ariaLabel | string | '' | 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. |
| inputName | string | '' | name attribute for the native input. |
| customClass | string | '' | Additional CSS classes on the root wrapper. |
| autocomplete | string | '' | `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. |
| inputMode | InputMode | '' | '' | Virtual-keyboard hint for mobile (e.g. 'numeric', 'email', 'tel'). |
| pattern | string | '' | Native validation regex (without anchors — anchored automatically). |
| minLength | number | 0 | Minimum length used by the built-in Validator and native `minlength`. |
| min | string | number | null | null | Native `min` for number/date/range types. |
| max | string | number | null | null | Native `max` for number/date/range types. |
| step | string | number | null | null | Native `step` for number/date/range types. |
| spellcheck | boolean | null | null | Native spellcheck toggle. null = browser default. |
| autofocus | boolean | false | Autofocus the control on render. |
Outputs
| Event | Payload type | Description |
|---|---|---|
| focused | FocusEvent | Emits when the input gains focus. |
| blurred | FocusEvent | Emits when the input loses focus. |
| submitted | string | Emits when Enter is pressed. |
| valueChange | string | Emits 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
| Name | Type | Default | Description |
|---|---|---|---|
| value | string (two-way) | '' | Current value. Use `[(value)]` for signal two-way binding. |
| type | InputType | 'text' | Input type. |
| multiline | boolean | false | Renders a `<textarea>` instead of `<input>`. |
| options | InputOption[] | [] | When set, renders a `<select>` element. Use `type` is ignored when options are provided. |
| label | string | '' | Label text shown above the input. |
| required | boolean | false | Marks the label with a red asterisk. |
| optionalTag | boolean | false | Optional label (replaces asterisk with a soft "(optional)" tag). |
| placeholder | string | '' | Placeholder text. |
| hint | string | '' | Helper text shown below the input (hidden when either error is set). |
| errorMessage | string | '' | Error message — switches state to `error` automatically when non-empty. |
| serverError | string | { readonly message: string } | null | null | A 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. |
| successMessage | string | '' | Success message — shown below when state is `success`. |
| variant | InputVariant | 'default' | Visual style. |
| size | InputSize | 'md' | Size. |
| state | InputState | 'default' | Explicit validation state override. Automatically set to `'error'` when `errorMessage` is non-empty. |
| leadingIcon | string | '' | 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. |
| trailingIcon | string | '' | Icon-library NAME for the trailing (right) icon — e.g. `'calendar'`. Was `trailingIconPath`, a raw SVG `d` string. |
| leadingAddon | string | '' | Short text prepended inside the input (e.g. `'https://'`, `'$'`). Ignored when `leadingIcon` is set. |
| trailingAddon | string | '' | Short text appended inside the input (e.g. `'.com'`, `'USD'`). Ignored when `trailingIcon` is set. |
| maxLength | number | 0 | Maximum character count shown as a counter below the input. Set to 0 to disable. |
| disabled | boolean | false | Disable the input. |
| readonly | boolean | false | Read-only mode. |
| loading | boolean | false | Show a loading spinner in the trailing position. |
| inputId | string | '' | id forwarded to the native input — required for external `<label for>`. |
| ariaLabel | string | '' | 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. |
| inputName | string | '' | name attribute for the native input. |
| customClass | string | '' | Additional CSS classes on the root wrapper. |
| autocomplete | string | '' | `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. |
| inputMode | InputMode | '' | '' | Virtual-keyboard hint for mobile (e.g. 'numeric', 'email', 'tel'). |
| pattern | string | '' | Native validation regex (without anchors — anchored automatically). |
| minLength | number | 0 | Minimum length used by the built-in Validator and native `minlength`. |
| min | string | number | null | null | Native `min` for number/date/range types. |
| max | string | number | null | null | Native `max` for number/date/range types. |
| step | string | number | null | null | Native `step` for number/date/range types. |
| spellcheck | boolean | null | null | Native spellcheck toggle. null = browser default. |
| autofocus | boolean | false | Autofocus the control on render. |
Outputs
| Event | Payload type | Description |
|---|---|---|
| focused | FocusEvent | Emits when the input gains focus. |
| blurred | FocusEvent | Emits when the input loses focus. |
| submitted | string | Emits when Enter is pressed. |
| valueChange | string | Emits 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.