Input Beta
Write a native <input><textarea>tg2Input<tg2-input-container>ngModelformControlNameformFieldtypeplaceholdermaxlengthreadonlyautocomplete
Form systems
The container has no value input or output — every form system Angular supports works the same way it always has, straight on the projected <input>
ngModel
<tg2-input-container label="Title">
<input tg2Input required [(ngModel)]="title" />
</tg2-input-container>Reactive forms
readonly form = new FormGroup({
email: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.email] })
});<form [formGroup]="form">
<tg2-input-container label="Email">
<input tg2Input type="email" formControlName="email" />
</tg2-input-container>
</form>Signal Forms
import { FormField, form, required } from '@angular/forms/signals';
readonly model = signal({ username: '' });
readonly userForm = form(this.model, path => {
required(path.username, { message: 'Username is required' });
});<tg2-input-container label="Username">
<input tg2Input [formField]="userForm.username" />
</tg2-input-container>No forms library
A plain [value](input)
<tg2-input-container label="Title">
<input tg2Input required [value]="title" (input)="title = $any($event.target).value" />
</tg2-input-container>States
| Large (default) | Medium | |
|---|---|---|
| Default | ||
| Filled | ||
| Disabled | ||
| Read-only | ||
| Error |
Label
"(optional)" is added to the label of any field that isn't required. Mark a field required where your form expects it (the requiredValidators.required{ required: true }required()showOptional="false"
Angular doesn't emit an event when validators change. After setValidators()addValidators()removeValidators()clearValidators()updateValueAndValidity()aria-requirederrors
| Default | Hidden | Optional | Floating |
|---|---|---|---|
Icons and clear button
| Icon left | Icon right | Clearable |
|---|---|---|
Characters remaining and textarea
| Characters remaining | Over the limit | Textarea |
|---|---|---|
A native maxlengthcharacterLimit
Going over the limit is a warning while the user types, not an error: the border, aria-invaliderrorMessagengModel[error]maxlength
Screen readers hear the count after the user pauses typing, through a hidden live region, so it isn't read out on every keystroke.
readonly message = new FormControl('', { validators: [Validators.required, Validators.maxLength(500)] });
<tg2-input-container
label="Message"
characterLimit="500"
showRemainingCharacters
errorMessage="Keep your message to 500 characters">
<textarea tg2Input [formControl]="message"></textarea>
</tg2-input-container>Errors from your own validation
By default the error shows once the Angular control is touched and invalid. If your errors are worked out somewhere else, for example in signals with no validators on the control, set [error]truearia-invalidfalse
readonly firstName = signal('');
readonly firstNameError = computed(() => (this.touched() || this.submitted()) && !this.firstName());
<tg2-input-container label="First name" errorMessage="Enter your first name" [error]="firstNameError()">
<input tg2Input required [ngModel]="firstName()" (ngModelChange)="firstName.set($event)" />
</tg2-input-container>Radius
Set radiussmallmediumlargetg-lighttg-dark
| small (4px) | medium (8px) | large (16px) |
|---|---|---|
API
tg2-input-container
The container has no value input or output — bind your form directive on the native element instead. aria-invalidaria-requiredaria-describedbyrequiredValidators.requiredrequired
| Input | Type | Default | Description |
|---|---|---|---|
label | string | — | The field's label text. |
showLabel | boolean | true | Visually hides the label. Screen readers still announce it. |
description | string | — | Helper text shown in the footer when there is no error or character count to show. |
errorMessage | string | — | Shown in the footer once the control is touched and invalid, or when errortrue |
error | boolean | — | Sets the error state directly, for validation outside the Angular forms API. Unset follows the control. |
showOptional | boolean | true | "(optional)" is appended to the label automatically when the field isn't required. Set false |
floatingLabel | boolean | false | Puts the label inside the field. Ignored when showLabel |
size | Tg2InputSizeEnummedium | large | large | Field height. Medium is 38px. Large is 48px, or 56px with a floating label. |
iconLeft | TangramIconKind | — | Decorative icon shown before the field. |
iconRight | TangramIconKind | — | Decorative icon shown after the field. |
clearable | boolean | false | Shows a clear button while the field has a value. Clears the native value and dispatches an input |
showRemainingCharacters | boolean | false | Needs characterLimitmaxlength |
characterLimit | number | — | Limit for the characters remaining counter. Unlike maxlengtherrorMessagemaxlength |
radius | small | medium | large | — | Corner radius (4px, 8px, 16px). Unset follows the theme: 8px, or 3px for tg-light and tg-dark. |
theme | tg2-light | tg2-dark | tg-light | tg-dark | tg2-light | Which visual design system the field uses. |
tg2Input
Selector: input[tg2Input], textarea[tg2Input]
| Input | Type | Description |
|---|---|---|
id | string | A consumer-supplied id for the native element. When omitted, an id is generated automatically. |
aria-describedby | string | Ids of your own elements that describe the field. They're kept, and the footer's id is added after them. Set it as aria-describedby="…"[aria-describedby]="…"[attr.aria-describedby] |
Try every option interactively on the Code Example page.