Directivea11y

Input

Attribute directive applied to a native <input> (or <textarea>). Because the styling lives on the real input, third-party directives like ngx-mask, custom validators, and [(ngModel)] compose naturally on the same element.

Installation

import {
  WrInput,
  WrInputGroup,
  WrInputPrefix,
  WrInputSuffix,
  WrPasswordToggle
} from 'ngwr/input';
import { FormsModule } from '@angular/forms';

@Component({
  imports: [
    WrInput,
    WrInputGroup,
    WrInputPrefix,
    WrInputSuffix,
    WrPasswordToggle,
    FormsModule,
  ],
})
export class MyComponent {
  text = signal('');
}

Basic usage

Value: Hello world
<input wrInput placeholder="Type here…" [(ngModel)]="text" />

Types

Set any native type — text, number, email, search, tel, url, password.

<input wrInput type="email" placeholder="[email protected]" />
<input wrInput type="number" placeholder="0" />
<input wrInput type="search" placeholder="Search" />

Prefix & suffix

Wrap in <wr-input-group> and mark sibling elements with [wrInputPrefix] / [wrInputSuffix]. The group owns the border and focus ring (via :focus-within).

$USDhttps://
<wr-input-group>
  <span wrInputPrefix>$</span>
  <input wrInput type="number" [(ngModel)]="amount" />
  <span wrInputSuffix>USD</span>
</wr-input-group>

Rounded

<input wrInput rounded placeholder="Rounded" />

Password reveal

<wr-password-toggle> flips its linked input's type attribute between password and text. Use a template ref to wire them up.

<wr-input-group>
  <input wrInput type="password" [(ngModel)]="password" #pwInput />
  <wr-password-toggle [for]="pwInput" />
</wr-input-group>

Input masking — with ngx-mask

ngwr does not ship a mask directive of its own, and deliberately does not wrap one either — a mask is input plumbing, not a look, so blessing the ecosystem's standard beats owning a second copy of it. ngx-mask is that standard: battle-tested, signal-compatible, MIT, and about 18 KB once minified and gzipped. Because [wrInput] is just a directive on the real <input>, it plugs in on the same element with zero ceremony.

Setup

// 1. Install ngx-mask as a peer dependency:
//    pnpm add ngx-mask

// 2. Provide it at bootstrap once (pass overrides for global defaults):
import { provideEnvironmentNgxMask } from 'ngx-mask';

bootstrapApplication(AppComponent, {
  providers: [
    provideEnvironmentNgxMask({
      thousandSeparator: ',',
      decimalMarker: '.',
    }),
  ],
});

// 3. Import the directive in any standalone component:
import { NgxMaskDirective } from 'ngx-mask';

@Component({
  imports: [NgxMaskDirective, WrInput, FormsModule],
})
export class MyForm {}

Common masks

<!-- Phone (US-style) -->
<input wrInput mask="(000) 000-0000" placeholder="(555) 555-5555" [(ngModel)]="phone" />

<!-- Credit card -->
<input wrInput mask="0000 0000 0000 0000" placeholder="4242 4242 4242 4242" [(ngModel)]="card" />

<!-- Expiry MM/YY -->
<input wrInput mask="00/00" placeholder="12/29" [(ngModel)]="expiry" />

<!-- CVC (3 digits) -->
<input wrInput mask="000" placeholder="123" [(ngModel)]="cvc" />

<!-- Date DD/MM/YYYY -->
<input wrInput mask="00/00/0000" placeholder="31/12/2026" [(ngModel)]="date" />

<!-- Money: separator with two-decimal precision -->
<wr-input-group>
  <span wrInputPrefix>$</span>
  <input wrInput mask="separator.2" [(ngModel)]="money" placeholder="1,234.56" />
</wr-input-group>

Full token reference (custom patterns, dynamic masks, locale config) — see the ngx-mask docs.

Disabled

<input wrInput placeholder="Disabled" disabled />

In a form, this is the one that behaves natively

[wrInput] styles a real <input>, so its form semantics are Angular's own — and they differ from every ngwr component in the catalog. Worth knowing before you mix the two in one FormGroup.

A native <input> binds through the DefaultValueAccessor Angular ships. Every ngwr value component — <wr-select>, <wr-input-number>, <wr-checkbox> and the rest — binds through Angular 22's forms bridge instead, because the library ships no ControlValueAccessor at all. Two consequences show up as soon as both are in the same form. updateOn: 'blur' and 'submit' hold here and are ignored by the components, and a { emitEvent: false } write repaints this field and not them. Neither is a bug in either half; the guide explains both and what to do about them.

[wrInput] directive

NameDescriptionTypeDefault
wrInputSelector. Applies NGWR input styling to a native <input> or <textarea>.attribute
sizeControl size.'sm' | 'md' | 'lg' | null'md'
roundedPill-shaped corners.boolean | nullfalse

<wr-input-group>

NameDescriptionTypeDefault
wr-input-groupWrapper for the input + prefix/suffix/toggle siblings.component
roundedPill-shaped corners.boolean | nullfalse

Prefix & suffix directives

NameDescriptionTypeDefault
[wrInputPrefix]Marks an element as the left affix.attribute
[wrInputSuffix]Marks an element as the right affix.attribute

<wr-password-toggle>

NameDescriptionTypeDefault
forrequiredThe linked password <input> reference.HTMLInputElement
showLabelAccessible name while the password is hidden — the button is icon-only. Falls back to the input.showPassword catalog key.string | nullnull
hideLabelAccessible name while the password is revealed. Falls back to the input.hidePassword catalog key.string | nullnull

CSS variables

Custom properties ngwr/input publishes. Each default below is declared on the component's own selector, so a :root override is shadowed by it — set them on that selector, on a wrapper you scope yourself, or inline on the element. Unlike the BEM class names, these are the supported way to restyle the component.

VariableDefaultDeclared on
--wr-input-bgvar(--wr-color-surface).wr-input +1 variant override
--wr-input-bordervar(--wr-color-outline).wr-input +2 variant overrides
--wr-input-colorvar(--wr-color-on-surface).wr-input +1 variant override
--wr-input-font-sizevar(--wr-control-font-size-md).wr-input +2 variant overrides
--wr-input-group-affixvar(--wr-color-on-surface-muted).wr-input-group
--wr-input-group-bgvar(--wr-color-surface).wr-input-group +1 variant override
--wr-input-group-bordervar(--wr-color-outline).wr-input-group +1 variant override
--wr-input-group-padding-x0.75rem.wr-input-group +1 variant override
--wr-input-group-radiusvar(--wr-control-radius-md).wr-input-group +1 variant override
--wr-input-group-ringtransparent.wr-input-group +1 variant override
--wr-input-line-heightvar(--wr-control-line-height-md).wr-input +2 variant overrides
--wr-input-padding-xvar(--wr-control-padding-x-md).wr-input +3 variant overrides
--wr-input-padding-yvar(--wr-control-padding-y-md).wr-input +2 variant overrides
--wr-input-placeholderrgba(var(--wr-color-on-surface-muted-rgb), 0.7).wr-input
--wr-input-radiusvar(--wr-control-radius-md).wr-input +3 variant overrides
--wr-input-ringtransparent.wr-input +2 variant overrides