Skip to main content

Input Masks

Tess UI Library fornisce utilità per applicare maschere di input per formattazione automatica dei dati inseriti dall'utente.

Panoramica

Le input masks migliorano l'esperienza utente fornendo:

  • Formattazione automatica: Applica pattern durante la digitazione
  • Validazione visiva: Feedback immediato sul formato
  • Prevenzione errori: Limita input a caratteri validi
  • Localizzazione: Supporto per formati locali

Masks Disponibili

Currency Mask

Formatta valori monetari.

import { CurrencyMaskDirective } from '@tess-ui-library/shared';

@Component({
standalone: true,
imports: [CurrencyMaskDirective, ReactiveFormsModule],
template: `
<input
type="text"
[formControl]="priceControl"
tessCurrencyMask
[locale]="'it-IT'"
[currency]="'EUR'"
/>
`,
})
export class ProductFormComponent {
priceControl = new FormControl(1234.56);
}

// Display: € 1.234,56

Opzioni

  • locale: Locale per formattazione (default: 'it-IT')
  • currency: Codice valuta ISO (default: 'EUR')
  • precision: Decimali (default: 2)

Phone Mask

Formatta numeri di telefono.

import { PhoneMaskDirective } from '@tess-ui-library/shared';

@Component({
standalone: true,
imports: [PhoneMaskDirective, ReactiveFormsModule],
template: `
<input
type="tel"
[formControl]="phoneControl"
tessPhoneMask
[countryCode]="'IT'"
/>
`,
})
export class ContactFormComponent {
phoneControl = new FormControl('');
}

// Input: 3331234567
// Display: +39 333 123 4567

Opzioni

  • countryCode: Codice paese ISO (default: 'IT')
  • format: Pattern personalizzato

Date Mask

Formatta date.

import { DateMaskDirective } from '@tess-ui-library/shared';

@Component({
standalone: true,
imports: [DateMaskDirective, ReactiveFormsModule],
template: `
<input
type="text"
[formControl]="dateControl"
tessDateMask
[format]="'dd/MM/yyyy'"
/>
`,
})
export class EventFormComponent {
dateControl = new FormControl('');
}

// Input: 08012026
// Display: 08/01/2026

Formati Supportati

  • dd/MM/yyyy (default)
  • MM/dd/yyyy
  • yyyy-MM-dd
  • Custom pattern

Credit Card Mask

Formatta numeri di carte di credito.

import { CreditCardMaskDirective } from '@tess-ui-library/shared';

@Component({
standalone: true,
imports: [CreditCardMaskDirective, ReactiveFormsModule],
template: `
<input
type="text"
[formControl]="cardControl"
tessCreditCardMask
maxlength="19"
/>
`,
})
export class PaymentFormComponent {
cardControl = new FormControl('');
}

// Input: 1234567890123456
// Display: 1234 5678 9012 3456

VAT/Tax ID Mask

Formatta Partita IVA italiana.

import { VatMaskDirective } from '@tess-ui-library/shared';

@Component({
standalone: true,
imports: [VatMaskDirective, ReactiveFormsModule],
template: `
<input
type="text"
[formControl]="vatControl"
tessVatMask
[country]="'IT'"
/>
`,
})
export class CompanyFormComponent {
vatControl = new FormControl('');
}

// Input: 12345678901
// Display: IT 12345678901

IBAN Mask

Formatta codici IBAN.

import { IbanMaskDirective } from '@tess-ui-library/shared';

@Component({
standalone: true,
imports: [IbanMaskDirective, ReactiveFormsModule],
template: `
<input
type="text"
[formControl]="ibanControl"
tessIbanMask
/>
`,
})
export class BankFormComponent {
ibanControl = new FormControl('');
}

// Input: IT60X0542811101000000123456
// Display: IT60 X054 2811 1010 0000 0012 3456

Custom Masks

Creare una Mask Custom

import { Directive, HostListener, ElementRef } from '@angular/core';

@Directive({
selector: '[appCustomMask]',
standalone: true,
})
export class CustomMaskDirective {
private el: HTMLInputElement;

constructor(private elementRef: ElementRef) {
this.el = this.elementRef.nativeElement;
}

@HostListener('input', ['$event'])
onInput(event: Event): void {
const input = event.target as HTMLInputElement;
let value = input.value;

// Rimuovi caratteri non validi
value = value.replace(/[^0-9]/g, '');

// Applica pattern personalizzato
// Esempio: XXX-XXX-XXX
if (value.length > 3) {
value = value.slice(0, 3) + '-' + value.slice(3);
}
if (value.length > 7) {
value = value.slice(0, 7) + '-' + value.slice(7, 10);
}

input.value = value;
}

@HostListener('blur')
onBlur(): void {
// Validazione finale al blur
if (this.el.value.length > 0 && this.el.value.length < 11) {
this.el.setCustomValidity('Formato non valido');
} else {
this.el.setCustomValidity('');
}
}
}

Pattern Generico

import { Directive, Input, HostListener, ElementRef } from '@angular/core';

@Directive({
selector: '[appPatternMask]',
standalone: true,
})
export class PatternMaskDirective {
@Input() pattern: string = ''; // es: '###-###-####'
@Input() placeholder: string = '#';

private el: HTMLInputElement;

constructor(private elementRef: ElementRef) {
this.el = this.elementRef.nativeElement;
}

@HostListener('input', ['$event'])
onInput(event: Event): void {
const input = event.target as HTMLInputElement;
let value = input.value.replace(/\D/g, '');
let formatted = '';
let valueIndex = 0;

for (let i = 0; i < this.pattern.length && valueIndex < value.length; i++) {
if (this.pattern[i] === this.placeholder) {
formatted += value[valueIndex];
valueIndex++;
} else {
formatted += this.pattern[i];
}
}

input.value = formatted;
}
}

// Uso
<input appPatternMask pattern="(###) ###-####" placeholder="#" />
// Input: 3331234567
// Display: (333) 123-4567

Integrazione con Form Validation

import { Component } from '@angular/core';
import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
import { PhoneMaskDirective } from '@tess-ui-library/shared';
import { phoneValidator } from '@tess-ui-library/core';

@Component({
standalone: true,
imports: [PhoneMaskDirective, ReactiveFormsModule],
template: `
<div class="field">
<label for="phone">Telefono</label>
<input
id="phone"
type="tel"
[formControl]="phoneControl"
tessPhoneMask
[countryCode]="'IT'"
/>
@if (phoneControl.errors?.['phone']) {
<small class="error">Numero di telefono non valido</small>
}
</div>
`,
})
export class ContactFormComponent {
phoneControl = new FormControl('', [
Validators.required,
phoneValidator,
]);
}

Best Practices

  1. Combina con validatori: Usa mask + validatori per garantire dati corretti
  2. Feedback visivo: Mostra errori di validazione sotto l'input
  3. Placeholder descrittivo: Indica il formato atteso
  4. Accessibilità: Usa aria-label e aria-describedby per screen reader
  5. Mobile friendly: Usa inputmode e type appropriati
  6. Performance: Debounce per operazioni costose
  7. Testing: Testa con vari input e edge cases

Esempi Completi

Form di Pagamento

@Component({
standalone: true,
imports: [
ReactiveFormsModule,
CreditCardMaskDirective,
DateMaskDirective,
],
template: `
<form [formGroup]="paymentForm" (ngSubmit)="onSubmit()">
<div class="field">
<label>Numero Carta</label>
<input
formControlName="cardNumber"
tessCreditCardMask
placeholder="1234 5678 9012 3456"
inputmode="numeric"
/>
</div>

<div class="field">
<label>Scadenza</label>
<input
formControlName="expiryDate"
tessDateMask
[format]="'MM/yy'"
placeholder="MM/YY"
inputmode="numeric"
/>
</div>

<div class="field">
<label>CVV</label>
<input
formControlName="cvv"
type="password"
maxlength="3"
placeholder="123"
inputmode="numeric"
/>
</div>

<button type="submit" [disabled]="paymentForm.invalid">
Paga
</button>
</form>
`,
})
export class PaymentFormComponent {
paymentForm = new FormGroup({
cardNumber: new FormControl('', [
Validators.required,
Validators.minLength(19),
]),
expiryDate: new FormControl('', [
Validators.required,
Validators.pattern(/^\d{2}\/\d{2}$/),
]),
cvv: new FormControl('', [
Validators.required,
Validators.pattern(/^\d{3}$/),
]),
});

onSubmit() {
if (this.paymentForm.valid) {
console.log('Payment data:', this.paymentForm.value);
}
}
}

Vedi Anche