Text input

<text-input> is built to work with Signal Forms with no adapter code at all. Signal Forms' FormField directive looks for a value model on a value control, and <text-input>'s value is a model(), so <text-input [formField]="f.name" /> is the entire integration. It also works as a plain two-way binding without a form at all: [(value)].

Import
import { TextInput, InputAccessoryView } from '@ng-native/components';
Template
<text-input><input-accessory-view> once they are in the component's imports
<text-input placeholder="Name" [formField]="profile.name" />

The Signal Forms contract

<text-input> carries the whole control contract FormField writes to, not just value: disabled and readonly both turn editable off (disabled also wins the announced accessibility state); invalid and touched are published as the data-invalid and data-touched attributes, since nothing native reads them - they exist for a stylesheet; and touch fires from the native blur event, because there is no DOM blur for Signal Forms to listen to instead.

text-input {
  border-width: 1px;
  border-color: #3a3a42;
}
text-input[data-invalid][data-touched] {
  border-color: #ff6b6b;
}

The point of writing data-invalid/data-touched only once both are true is the usual one: a field an app has not touched yet should not look broken before anyone has had a chance to fill it in.

Controlled, as in React Native

Bind value and the field shows what your state says. A keystroke emits valueChange and changeText; whatever your state holds once the handler has run is what the field ends up showing. Take the text as typed, refuse it, or rewrite it:

<!-- Digits only: anything else leaves the field as it was. -->
<text-input [value]="pin()" (changeText)="isDigits($event) && pin.set($event)" />

<!-- Shows what is typed in capitals, as it is typed. -->
<text-input [value]="code()" (changeText)="code.set($event.toUpperCase())" />

When your state takes the text as typed, native already shows it and nothing is sent back. When it refuses or rewrites it, native is showing text your state does not hold, and a refused keystroke leaves your binding where it was, so there is no prop change to carry the correction. Once the change detection pass the keystroke started has finished, <text-input> compares value with the text native reported and, if they differ, sends React Native's setTextAndSelection command. A value set from code after the user has typed goes the same way.

Any binding makes the field controlled, one-way [value] included, so a field bound one way with nothing handling the change cannot be typed into, as in React Native. Decide in the handler, and do it synchronously: the comparison runs once the pass has finished, so a value that arrives later is compared as a refusal and then applied when it arrives. Leave value unbound and the field keeps what is typed. [formField] counts as a binding, and since a form takes every value the control gives it, typing into a form field sends nothing back.

That command carries the same counter as the rest of the typing protocol, the one React Native uses to keep fast typing safe: native reports each change with a counter, the component sends the latest one back, and native ignores anything older than what it already has. Without it, typing fast into a controlled field drops characters. None of this is something an app manages; it is what makes binding [(value)] straight to a signal safe. <switch>, on the switch page, is controlled the same way.

Keyboards and behavior

keyboardType picks the keyboard ('email-address', 'number-pad', 'phone-pad' and the rest); returnKeyType labels the return key, and submitBehavior decides what pressing it does ('submit', 'blurAndSubmit', or 'newline' - the default on a multiline field). multiline allows more than one line, secureTextEntry hides what is typed, autoCapitalize and autoCorrect control the usual typing assists, and maxLength is enforced natively so nothing flickers past the limit before being trimmed back.

<text-input> exposes focus(), blur(), clear(), setSelection(start, end?) and isFocused() as methods, reachable through a template reference or nativeRef. (changeText) carries just the new string, matching React Native's onChangeText; (change), (focus), (blur), (submitEditing), (endEditing), (selectionChange), (keyPress) and (contentSizeChange) are the raw element events.

text-inputdirective@ng-native/components
import { TextInput } from '@ng-native/components';and add TextInput to the component's imports

A text field, wired for signal forms. Commits as TextInput , single or multi line by prop.

Inputs

disabled
unknown

Refuse input and announce as disabled. Wins over editable .

readonly
unknown

Refuse input, though still announced as enabled. Wins over editable .

invalid
boolean = false

Published as data-invalid ; nothing native reads it.

touched
boolean = false

Published as data-touched ; nothing native reads it.

multiline
unknown

Allow more than one line.

scrollEnabled
unknown

iOS: whether a multiline field scrolls its text; off, it grows with it instead.

editable
unknown

Set to false to make the field read-only.

placeholder
string

Shown while the field is empty.

placeholderTextColor
string

keyboardType
KeyboardType

Which keyboard to show.

returnKeyType
ReturnKeyType

The label on the return key.

submitBehavior
SubmitBehavior

What return does. Defaults to blurAndSubmit on one line and newline on many.

secureTextEntry
unknown

Hide what is typed, for passwords.

autoCapitalize
'none' | 'sentences' | 'words' | 'characters'

When the keyboard capitalises. Defaults to sentences .

autoCorrect
unknown

Auto-correct while typing. Defaults to true.

autoFocus
unknown

Focus the field as soon as it mounts.

maxLength
unknown

The most characters allowed, enforced natively so nothing flickers.

numberOfLines
unknown

Android: the height of a multiline field, in lines.

selection
{ readonly start: number; readonly end?: number }

The selected range, or the caret when start equals end .

selectionColor
string

selectTextOnFocus
unknown

Select everything on focus.

caretHidden
unknown

contextMenuHidden
unknown

Disable the copy, paste and share menu.

textAlign
'left' | 'center' | 'right'

allowFontScaling
unknown

maxFontSizeMultiplier
unknown

inputAccessoryViewID
string

iOS: the nativeID of an <input-accessory-view> to dock above the keyboard.

clearButtonMode
'never' | 'while-editing' | 'unless-editing' | 'always'

iOS: when the clear button shows.

clearTextOnFocus
unknown

iOS: empty the field on focus.

enablesReturnKeyAutomatically
unknown

iOS: disable the return key while the field is empty.

keyboardAppearance
'default' | 'light' | 'dark'

iOS: the keyboard's colour scheme.

passwordRules
string

iOS: rules for a generated password, in Apple's Password Rules syntax.

spellCheck
unknown

iOS: underline misspellings. Follows autoCorrect by default.

smartInsertDelete
unknown

iOS: add and remove spaces around pasted and deleted words.

dataDetectorTypes
string | readonly string[]

iOS, multiline: turn phone numbers, links and addresses into taps.

textContentType
string

iOS: what the field holds, so the system can autofill it.

autoComplete
string

Android: the autofill hint.

underlineColorAndroid
string = 'transparent'

Android: the underline colour, transparent by default.

cursorColor
string

Android: the caret colour.

selectionHandleColor
string

Android: the selection handle colour.

textAlignVertical
'auto' | 'top' | 'bottom' | 'center'

Android: where text sits in a tall field.

importantForAutofill
'auto' | 'no' | 'noExcludeDescendants' | 'yes' | 'yesExcludeDescendants'

Android: whether autofill may fill this field.

showSoftInputOnFocus
unknown

Android: set to false to focus without raising the keyboard.

disableFullscreenUI
unknown

Android: keep the field in place in landscape rather than going full screen.

inlineImageLeft
string

Android: a drawable resource shown at the left of the field.

inlineImagePadding
unknown

textBreakStrategy
'simple' | 'highQuality' | 'balanced'

Android: the line-breaking strategy.

Two-way

value
string = ''

Outputs

changeText
string

The new text alone, on every native change.

touch
void

Focus left the field. What Signal Forms marks a field touched from.

Methods

focus(): void

Bring the keyboard up on this field. A view command, so it reaches native directly.

clear(): void

Empty the field.

setSelection(start: number, end = start): void

Move the caret, or select a range.

isFocused(): boolean

Whether this field currently has the keyboard.

Props a browser has no name for

Several inputs exist only because a native keyboard is a different object than an <input>: textContentType and autoComplete hint at autofill (a password manager, a one-time code) the way autocomplete does on the web, but with platform-specific values. passwordRules (iOS) constrains what a generated password looks like. On iOS, dataDetectorTypes makes recognised links and phone numbers tappable when multiline is true and editable is false. keyboardAppearance (iOS) sets the keyboard's own light or dark look independent of the app's theme, and showSoftInputOnFocus lets a field take focus (for a caret and a custom picker) without the system keyboard appearing at all.

Input accessory view

<input-accessory-view> docks a bar above the keyboard on iOS. Pair it with a <text-input> by giving the view a nativeID and the input the same string as inputAccessoryViewID. Android has no native counterpart to this and the element commits as a plain view, so content placed inside it simply sits inert rather than floating above the keyboard.

input-accessory-viewdirective@ng-native/components
import { InputAccessoryView } from '@ng-native/components';and add InputAccessoryView to the component's imports

A bar docked above the keyboard, iOS only. Pair it with a text input by giving this view a nativeID and the input the same inputAccessoryViewID .

Inputs

backgroundColor
string

The bar's background.

Angular components as native iOS and Android views, built and shipped with Expo.

An alpha. MIT licensed. Sponsor its development.

An independent project, not affiliated with or endorsed by Google, the Angular team or Expo. Angular is a trademark of Google LLC.