Skip to main content
cngx-src documentation

CngxInputMask

DirectivePrimaryv0.1.0WCAG AA

projects/forms/input/input-mask.directive.ts

Import#

import { CngxInputMask } from '@cngx/forms/input'

Description#

Pattern-based input mask directive.

Supports custom patterns, locale-aware presets, multiple patterns (separated by |), prefix/suffix, custom tokens, and character transforms.

Mask tokens

Token Description Regex
0 Required digit [0-9]
9 Optional digit [0-9]?
A Required letter [a-zA-Z]
a Optional letter [a-zA-Z]?
* Required alphanumeric [a-zA-Z0-9]
\\ Escape next char as literal -

Built-in presets

Pass a preset name instead of a pattern. Region suffix optional (defaults to LOCALE_ID).

Preset Example Notes
date cngxInputMask="date" Locale-aware DD/MM/YYYY or MM/DD/YYYY
date:short cngxInputMask="date:short" 2-digit year
time / time:24 cngxInputMask="time" HH:MM (24h)
time:12 cngxInputMask="time:12" HH:MM AM/PM
datetime cngxInputMask="datetime" Date + time
phone cngxInputMask="phone:CH" Country-specific
creditcard cngxInputMask="creditcard" Amex/Visa/MC auto-switch
iban cngxInputMask="iban:CH" Country-specific grouping
zip cngxInputMask="zip:DE" Country-specific
ip / ipv4 cngxInputMask="ip" 099.099.099.099
mac cngxInputMask="mac" AA:AA:AA:AA:AA:AA

Multiple patterns

Separate patterns with | - the directive selects the best match based on input length:

<input cngxInputMask="(00) 0000-0000|(00) 00000-0000" />
<!-- Phone (locale-aware) -->
<input cngxInputMask="phone" />

<!-- Date (locale-aware) -->
<input cngxInputMask="date" />

<!-- Custom pattern with prefix -->
<input cngxInputMask="000.000.000-00" [prefix]="'CPF: '" />

<!-- Custom token: hex color -->
<input cngxInputMask="\\#HHHHHH" [customTokens]="{ H: { pattern: /[0-9a-fA-F]/, transform: c => c.toUpperCase() } }" />

<!-- Credit card with auto-format switching -->
<input cngxInputMask="creditcard" />

https://cngxjs.github.io/cngx/examples/#/forms/input/mask/custom-pattern https://cngxjs.github.io/cngx/examples/#/forms/input/mask/custom-tokens-and-transform https://cngxjs.github.io/cngx/examples/#/forms/input/mask/locale-presets

Metadata#

Host#

Providers#

Relationships

Index#

Inputs#

clearOnBlur#boolean
input()

Whether to clear the input when focus is lost and the mask is incomplete.

default false
input()

Custom token definitions beyond the built-in set.

forceAlternate#number | null
input()

Force the Nth |-alternate, bypassing the length-based pick. Clamped to the available range; null (default) restores length-based selection. Changing it never clears value - the auto-clear watches mask(), which this leaves untouched.

default null
guide#boolean | undefined
input()

Whether to guide cursor to the next empty position. Falls back to global config.

includeLiterals#boolean
input()

Whether to include literal chars in the raw value.

default false
input()Required

Mask pattern, preset name, or |-separated patterns.

default { alias: 'cngxInputMask' }
placeholder#string | undefined
input()

Placeholder char shown for unfilled positions. Falls back to global config.

prefix#string
input()

Static text prepended to the display value (not part of mask or raw value).

default ''
suffix#string
input()

Static text appended to the display value (not part of mask or raw value).

default ''
value#string
model()

Primary value channel — raw unmasked value (digits/letters only, no literals unless includeLiterals).

default '', { alias: 'value' }

Outputs#

value#string
model()

Primary value channel — raw unmasked value (digits/letters only, no literals unless includeLiterals).

Instance Properties#

currentPattern#unknown
Readonly

The currently active pattern (useful when using multi-pattern or presets).

this.activePattern
rawValue#Signal
Readonly
Read `value` directly. Kept one release for migration.
this.value
transform#unknown
Readonly

Transform function applied to each accepted character before insertion.

input<((char: string) => string) | undefined>(undefined)

Methods#

clear#void

Clear the mask value.

handleFocus#void
Protected
setValue#void
setValue(raw: string)

Programmatically set the raw value. Invalid chars are filtered out.

@paramrawstring

HostBindings#

BindingExpression
[attr.aria-placeholder]ariaPlaceholder()

HostListeners#

EventHandler
(beforeinput)beforeinput()
(keydown)keydown()
(mousedown)mousedown()
(focus)focus()
(mouseup)mouseup()
(blur)blur()
(paste)paste()

All presets

import { ChangeDetectionStrategy, Component, LOCALE_ID } from '@angular/core';
import { CngxInputMask } from '@cngx/forms/input';

/**
 * The full CngxInputMask preset spectrum on one page.
 *
 * Each field uses a built-in preset string - no custom token map needed. The
 * locale-aware presets (`date`, `datetime`) follow the `en-US` `LOCALE_ID`
 * provided below; switch it to `de-DE` to see the separators flip. Region
 * presets (`phone:DE`, `iban:CH`, `zip:GB`) lazy-load their table on first
 * use, so they settle a tick after render; the static presets (`time`,
 * `creditcard`, `ip`, `mac`) and custom token patterns render immediately.
 */
@Component({
  selector: 'app-root',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [CngxInputMask],
  // en-US drives the locale-aware date/datetime separators. Try 'de-DE'.
  providers: [{ provide: LOCALE_ID, useValue: 'en-US' }],
  template: `
    <div style="display:grid;gap:0.85rem;max-width:30rem">
      @for (f of fields; track f.mask) {
        <label style="display:grid;gap:0.25rem">
          <span style="font-size:0.8125rem;font-weight:600">{{ f.label }}</span>
          <input
            [cngxInputMask]="f.mask"
            [prefix]="f.prefix ?? ''"
            #m="cngxInputMask"
            style="font:inherit;padding:0.4rem 0.55rem;border:1px solid #cbd5e1;border-radius:0.375rem"
          />
          <small style="opacity:0.65">
            <code>{{ f.mask }}</code> &middot; raw: {{ m.value() || '(empty)' }}
          </small>
        </label>
      }
    </div>
  `,
})
export class AllPresetsExample {
  protected readonly fields: ReadonlyArray<{ label: string; mask: string; prefix?: string }> = [
    { label: 'Date (locale)', mask: 'date' },
    { label: 'Date + time', mask: 'datetime' },
    { label: 'Time (24h)', mask: 'time' },
    { label: 'Credit card (Amex/Visa auto-switch)', mask: 'creditcard' },
    { label: 'Phone (Germany)', mask: 'phone:DE' },
    { label: 'IBAN (Switzerland)', mask: 'iban:CH' },
    { label: 'Postal code (UK)', mask: 'zip:GB' },
    { label: 'IPv4 address', mask: 'ip' },
    { label: 'MAC address', mask: 'mac' },
    { label: 'Custom pattern + prefix', mask: 'AA 000 000', prefix: 'CH-' },
  ];
}
export { AllPresetsExample as AppComponent };

Build your own pattern

import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { CngxInputMask } from '@cngx/forms/input';

/**
 * Build your own mask pattern live.
 *
 * Type a pattern into the top field and the masked input below re-targets to
 * it through `[cngxInputMask]="pattern()"`. Tokens: `0` digit, `A` letter,
 * `*` alphanumeric, `9` optional digit, `a` optional letter; any other
 * character is a literal, and `\\` escapes a token char into a literal.
 * Changing the pattern clears the entered value - that is the directive's
 * documented auto-clear on a mask-string change.
 */
@Component({
  selector: 'app-root',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [CngxInputMask],
  template: `
    <div style="display:grid;gap:0.85rem;max-width:30rem">
      <label style="display:grid;gap:0.25rem">
        <span style="font-size:0.8125rem;font-weight:600">Mask pattern</span>
        <input
          [value]="pattern()"
          (input)="pattern.set(asValue($event))"
          spellcheck="false"
          style="font:inherit;padding:0.4rem 0.55rem;border:1px solid #cbd5e1;border-radius:0.375rem"
        />
      </label>

      <label style="display:grid;gap:0.25rem">
        <span style="font-size:0.8125rem;font-weight:600">Your masked input</span>
        <input
          [cngxInputMask]="pattern()"
          #m="cngxInputMask"
          style="font:inherit;padding:0.4rem 0.55rem;border:1px solid #cbd5e1;border-radius:0.375rem"
        />
      </label>

      <small style="opacity:0.7">Display: {{ m.maskedValue() }} &middot; raw: {{ m.value() || '(empty)' }}</small>

      <fieldset style="border:1px solid #e2e8f0;border-radius:0.5rem;padding:0.6rem 0.75rem;display:grid;gap:0.4rem">
        <legend style="font-size:0.8125rem;font-weight:600;padding:0 0.3rem">Tokens</legend>
        @for (t of tokens; track t.token) {
          <div style="display:flex;gap:0.5rem;font-size:0.8125rem">
            <code style="min-width:1.5rem">{{ t.token }}</code>
            <span style="opacity:0.75">{{ t.meaning }}</span>
            <button
              type="button"
              (click)="append(t.token)"
              style="margin-left:auto;font:inherit;font-size:0.75rem;padding:0.1rem 0.45rem;border:1px solid #cbd5e1;border-radius:0.3rem;background:#f8fafc;cursor:pointer"
            >
              add
            </button>
          </div>
        }
      </fieldset>

      <div style="display:flex;gap:0.4rem;flex-wrap:wrap">
        @for (p of presets; track p) {
          <button
            type="button"
            (click)="pattern.set(p)"
            style="font:inherit;font-size:0.75rem;padding:0.2rem 0.55rem;border:1px solid #cbd5e1;border-radius:0.3rem;background:#f8fafc;cursor:pointer"
          >
            {{ p }}
          </button>
        }
      </div>
    </div>
  `,
})
export class PatternBuilderExample {
  protected readonly pattern = signal('(000) 000-0000');

  protected readonly tokens: ReadonlyArray<{ token: string; meaning: string }> = [
    { token: '0', meaning: 'required digit' },
    { token: 'A', meaning: 'required letter' },
    { token: '*', meaning: 'letter or digit' },
    { token: '9', meaning: 'optional digit' },
    { token: 'a', meaning: 'optional letter' },
  ];

  protected readonly presets: readonly string[] = [
    '(000) 000-0000',
    '0000 0000 0000 0000',
    'AA-00-AA',
    '00:00',
  ];

  protected asValue(event: Event): string {
    return (event.target as HTMLInputElement).value;
  }

  protected append(token: string): void {
    this.pattern.update((p) => p + token);
  }
}
export { PatternBuilderExample as AppComponent };