# Tel

Use `ui-tel` for customer contact fields, support callbacks, escalation paths, and any workflow that captures phone numbers. It inherits the shared field API for labels, help text, size, variant, readonly, disabled, and validation messaging while using telephone-friendly input semantics.

## Import
```ts
import { TelComponent } from 'ui';
```

## Basic telephone fields
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TelComponent } from 'ui';

@Component({
  selector: 'app-tel-basic-demo',
  standalone: true,
  imports: [FormsModule, TelComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%">
      <div
        style="flex:1 1 18rem;min-width:16rem;display:flex;flex-direction:column;gap:1rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="display:flex;flex-direction:column;gap:0.25rem">
          <div style="font-size:0.9375rem;font-weight:600">Primary contact number</div>
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Good default for account, customer, or workspace contact details.
          </div>
        </div>

        <ui-tel
          label="Phone number"
          placeholder="+1 (555) 123-4567"
          helpText="Use international format when the number may be called across regions."
        />
      </div>

      <div
        style="flex:1 1 18rem;min-width:16rem;display:flex;flex-direction:column;gap:1rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="display:flex;flex-direction:column;gap:0.25rem">
          <div style="font-size:0.9375rem;font-weight:600">Editable current number</div>
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Shows the built-in clear action when a value is already present.
          </div>
        </div>

        <ui-tel
          label="Support line"
          placeholder="+48 600 700 800"
          [(ngModel)]="supportLine"
          [ngModelOptions]="{ standalone: true }"
          helpText="Use clear to replace the number quickly."
        />
      </div>
    </div>
  `,
})
export class TelBasicDemoComponent {
  protected supportLine = '+48 600 700 800';
}
```

## Layout, size, and variant
```ts
import { Component } from '@angular/core';
import { TelComponent } from 'ui';

@Component({
  selector: 'app-tel-layout-demo',
  standalone: true,
  imports: [TelComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:46rem">
      <div
        style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="flex:1 1 15rem;min-width:14rem">
          <ui-tel
            label="Compact extension"
            size="small"
            inputVariant="filled-lighter"
            placeholder="555-0109"
          />
        </div>

        <div style="flex:1 1 15rem;min-width:14rem">
          <ui-tel
            label="Desk phone"
            labelPosition="before"
            size="medium"
            inputVariant="filled-gray"
            placeholder="+1 (555) 987-6543"
          />
        </div>
      </div>

      <div
        style="display:flex;flex-direction:column;gap:0.875rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="font-size:0.9375rem;font-weight:600">Prominent callback field</div>
        <ui-tel
          label="Callback number"
          size="large"
          inputVariant="filled"
          placeholder="+44 20 7946 0958"
          helpText="Use a larger field when phone contact is a primary action in the flow."
        />
      </div>
    </div>
  `,
})
export class TelLayoutDemoComponent {}
```

## Readonly, disabled, and inline error states
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TelComponent } from 'ui';

@Component({
  selector: 'app-tel-states-demo',
  standalone: true,
  imports: [FormsModule, TelComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%">
      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-tel
          label="Readonly emergency contact"
          [readonly]="true"
          [(ngModel)]="readonlyNumber"
          [ngModelOptions]="{ standalone: true }"
          helpText="Useful when the user can see the number but not edit it here."
        />
      </div>

      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-tel
          label="Disabled hotline"
          [disabled]="true"
          placeholder="+1 (555) 000-0000"
          helpText="Disabled removes interaction entirely."
        />
      </div>

      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-tel
          label="Inline format check"
          [(ngModel)]="draftNumber"
          [ngModelOptions]="{ standalone: true }"
          [errorText]="draftError"
          helpText="Example: +48 600 700 800"
        />
      </div>
    </div>
  `,
})
export class TelStatesDemoComponent {
  protected readonlyNumber = '+1 (555) 830-2040';
  protected draftNumber = '12';

  protected get draftError(): string {
    const normalized = this.draftNumber.replace(/[^\d+]/g, '');
    if (!normalized.length) {
      return '';
    }
    return normalized.length < 7 ? 'Enter a longer phone number.' : '';
  }
}
```

## Validation with reactive forms
```ts
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { ButtonComponent, TelComponent } from 'ui';

@Component({
  selector: 'app-tel-validation-demo',
  standalone: true,
  imports: [ButtonComponent, ReactiveFormsModule, TelComponent],
  template: `
    <form
      [formGroup]="phoneForm"
      style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:34rem"
      (ngSubmit)="markTouched()"
    >
      <ui-tel
        label="SMS verification number"
        placeholder="+1 (555) 123-4567"
        helpText="Required. Use at least 7 digits."
        formControlName="phone"
        [errorText]="phoneError"
      />

      <div style="display:flex;flex-wrap:wrap;gap:0.75rem">
        <ui-button type="submit">Validate</ui-button>
        <ui-button type="button" appearance="outline" (click)="fillExample()"
          >Use example</ui-button
        >
      </div>
    </form>
  `,
})
export class TelValidationDemoComponent {
  protected readonly phoneForm = new FormGroup({
    phone: new FormControl('', {
      nonNullable: true,
      validators: [Validators.required, Validators.minLength(7)],
    }),
  });

  protected get phoneError(): string {
    const control = this.phoneForm.controls.phone;
    if (!control.touched && !control.dirty) {
      return '';
    }
    if (control.hasError('required')) {
      return 'Phone number is required.';
    }
    if (control.hasError('minlength')) {
      return 'Enter at least 7 characters.';
    }
    return '';
  }

  protected markTouched(): void {
    this.phoneForm.markAllAsTouched();
  }

  protected fillExample(): void {
    this.phoneForm.controls.phone.setValue('+48 600 700 800');
    this.phoneForm.controls.phone.markAsTouched();
  }
}
```

## Contact routing form
```ts
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { ButtonComponent, TelComponent } from 'ui';

@Component({
  selector: 'app-tel-contact-form-demo',
  standalone: true,
  imports: [ButtonComponent, ReactiveFormsModule, TelComponent],
  template: `
    <form
      [formGroup]="contactForm"
      style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%;max-width:54rem"
    >
      <div
        style="flex:1 1 22rem;min-width:18rem;display:flex;flex-direction:column;gap:1rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="display:flex;flex-direction:column;gap:0.25rem">
          <div style="font-size:0.9375rem;font-weight:600">Contact routing</div>
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Telephone fields are often grouped by purpose: primary contact, escalation, and
            after-hours support.
          </div>
        </div>

        <ui-tel
          label="Primary number"
          placeholder="+1 (555) 123-4567"
          formControlName="primary"
          helpText="Shown on the workspace profile."
        />

        <ui-tel
          label="Escalation number"
          placeholder="+1 (555) 987-6543"
          formControlName="escalation"
          inputVariant="filled-gray"
          helpText="Used by internal support only."
        />

        <ui-tel
          label="After-hours line"
          placeholder="+1 (555) 000-1111"
          formControlName="afterHours"
          helpText="Optional fallback for urgent incidents."
        />

        <div
          style="display:flex;gap:0.75rem;flex-wrap:wrap;align-items:center;padding:0.75rem 0.875rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:0.875rem;background:var(--color-neutral-background-rest)"
        >
          <ui-button type="button" variant="primary">Save contacts</ui-button>
          <ui-button type="button" variant="secondary" appearance="outline" (click)="reset()">
            Reset
          </ui-button>
        </div>
      </div>

      <div
        style="flex:0 0 18rem;min-width:16rem;padding:0.875rem 1rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background2-rest)"
      >
        <p
          style="margin:0 0 0.5rem;font-size:0.75rem;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;color:var(--color-neutral-foreground2-rest)"
        >
          Current values
        </p>
        <div
          style="display:flex;flex-direction:column;gap:0.5rem;font-size:0.875rem;line-height:1.4"
        >
          <div style="display:flex;justify-content:space-between;gap:1rem">
            <span style="color:var(--color-neutral-foreground2-rest)">Primary</span>
            <strong style="font-weight:600;color:var(--color-neutral-foreground-rest)">{{
              contactForm.controls.primary.value || 'None'
            }}</strong>
          </div>
          <div style="display:flex;justify-content:space-between;gap:1rem">
            <span style="color:var(--color-neutral-foreground2-rest)">Escalation</span>
            <strong style="font-weight:600;color:var(--color-neutral-foreground-rest)">{{
              contactForm.controls.escalation.value || 'None'
            }}</strong>
          </div>
          <div style="display:flex;justify-content:space-between;gap:1rem">
            <span style="color:var(--color-neutral-foreground2-rest)">After-hours</span>
            <strong style="font-weight:600;color:var(--color-neutral-foreground-rest)">{{
              contactForm.controls.afterHours.value || 'None'
            }}</strong>
          </div>
        </div>
      </div>
    </form>
  `,
})
export class TelContactFormDemoComponent {
  protected readonly defaults = {
    primary: '+48 600 700 800',
    escalation: '+48 500 400 300',
    afterHours: '',
  };

  protected readonly contactForm = new FormGroup({
    primary: new FormControl(this.defaults.primary, { nonNullable: true }),
    escalation: new FormControl(this.defaults.escalation, { nonNullable: true }),
    afterHours: new FormControl(this.defaults.afterHours, { nonNullable: true }),
  });

  protected reset(): void {
    this.contactForm.reset(this.defaults);
  }
}
```

## Callback request panel
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ButtonComponent, TelComponent } from 'ui';

@Component({
  selector: 'app-tel-support-panel-demo',
  standalone: true,
  imports: [ButtonComponent, FormsModule, TelComponent],
  template: `
    <div
      style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:42rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <div style="display:flex;flex-direction:column;gap:0.375rem">
        <div style="font-size:1rem;font-weight:600">Callback request panel</div>
        <div
          style="font-size:0.875rem;color:var(--color-neutral-foreground2-rest);line-height:1.45"
        >
          A stronger end-to-end example: collect the preferred callback number, show service window
          context, and keep the next action nearby.
        </div>
      </div>

      <ui-tel
        label="Preferred callback number"
        placeholder="+44 20 7946 0958"
        [(ngModel)]="callbackNumber"
        [ngModelOptions]="{ standalone: true }"
        helpText="Support calls back Monday to Friday, 9:00-17:00 CET."
      />

      <div
        style="display:flex;gap:0.75rem;flex-wrap:wrap;align-items:center;padding:0.75rem 0.875rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:0.875rem;background:var(--color-neutral-background-rest)"
      >
        <ui-button type="button" variant="primary">Request callback</ui-button>
        <ui-button type="button" variant="secondary" appearance="outline"
          >Use account number</ui-button
        >
      </div>
    </div>
  `,
})
export class TelSupportPanelDemoComponent {
  protected callbackNumber = '+44 20 7946 0958';
}
```

## Accessibility

### Label and name
Prefer a visible `label` so the phone number's purpose is explicit, especially when multiple contact fields appear together. Help and error text contribute through `aria-describedby`.

### Native telephone semantics
The inner input uses native `type="tel"`, which helps mobile browsers show phone-friendly keyboards and aligns the field with browser autofill expectations. When `autocomplete` is omitted, the inner input falls back to `tel`.

### Keyboard and actions
This is a standard text-entry field backed by a native telephone input. Clear and call affordances are exposed in the field chrome when the field is editable.

| Aspect | Behavior |
| --- | --- |
| focus | native tel input receives focus |
| typing | native tel input behavior |
| clear action | appears only when the field has a value and is editable |
| call action | stays visible while editable to reinforce the contact purpose |
| readonly / disabled | actions are hidden and direct editing is blocked |
