Lynx/Modules/Zero/Input
@sigx/lynx-zero · Beta · Component library

Input#

A single-line text field on the native Lynx <input>, carrying zero's input anatomy. The value is a plain string model. The painted box is a <view> around the native field, because iOS never repaints a native text field's styles after mount, so every state that paints lives on a view.

The parts are the same as the web component's. See Input in @sigx/zero for the shared contract. This page covers what is different on Lynx.

Import#

TSX
import { Input } from '@sigx/lynx-zero';

Input is a compound with Root, Label, Control, Input, Adornment, ClearTrigger and VisibilityTrigger. <Input> is the same component as <Input.Root>.

Usage#

TSX
import { component, signal } from '@sigx/lynx';
import { Input } from '@sigx/lynx-zero';

export const Email = component(() => {
    const form = signal({ email: '' });
    return () => (
        <Input.Root model={() => form.email} type="email" enterkeyhint="next">
            <Input.Label>Email</Input.Label>
            <Input.Control>
                <Input.Adornment placement="start"><text>@</text></Input.Adornment>
                <Input.Input placeholder="you@example.com" onConfirm={() => focusNext()} />
                <Input.ClearTrigger />
            </Input.Control>
        </Input.Root>
    );
});

Input.Control is the box the skin paints. Put Input.Input, the native field, inside it, with any adornments and triggers.

The model is the only value channel#

The model is a string, written on every keystroke. The Root's state is the model the native <input> binds, so Lynx's own model handling owns the write-back, including the deferred initial value on iOS. Leave model off and pass defaultValue to keep the text inside the component. valueChange fires either way.

There is no value prop. Bind model instead.

Passwords#

type="password" hides the characters. Input.VisibilityTrigger toggles them, through the visible model:

TSX
<Input.Root type="password" model={() => form.password} model:visible={() => ui.shown}>
    <Input.Control>
        <Input.Input />
        <Input.VisibilityTrigger />
    </Input.Control>
</Input.Root>

Use model:visible to bind it, or defaultVisible and visibleChange to leave it uncontrolled. A shown password renders as a text field. The trigger keeps one name ("Show password" by default) and announces its on state as selected, as a toggle button does. Its default slot receives { visible } so you can swap an icon. On any type other than password, visible changes nothing.

Clear trigger#

Input.ClearTrigger empties the value and focuses the field. It renders nothing while the field is empty, and it is inert while the field is disabled or read-only. With no children it draws ×, named "Clear" for the reader.

Both triggers use catchtap, so a press on a trigger never also lands on the control.

Focus#

Lynx has no <label for> and no element.focus(). A tap on Input.Label, on the control's padding or on an adornment focuses the native field through its focus UI method. Inside a Field.Root, a tap on Field.Label does the same. A disabled field is never focused.

Native focus stamps focus-visible on control and input. A text field shows its ring on any focus, the same way the web's :focus-visible matches every focused text input. The skin draws the ring on control.

autofocus focuses the field when it mounts.

Keyboard attributes#

Zero's web attributes map onto the Lynx <input> set:

PropOn Lynx
typetext, email, password and tel pass through. search and url are text fields; a search field's Enter key says search unless enterkeyhint says otherwise.
inputmodeOn a text field, numeric picks the digit pad and decimal the number pad. tel and email pick those fields. password, email and tel fields keep their own type.
enterkeyhintMaps to confirm-type. Lynx supports done, go, next, search and send; enter and previous leave the platform default.
spellcheckios-spell-check, iOS only.
autocorrectios-auto-correct, iOS only. Use off for codes, usernames and addresses.
maxlengthPassed through as a whole, non-negative count.

An optional string you do not set never reaches the native element. iOS would receive it as NSNull.

Read-only fields#

readonly keeps the field announced and selectable, and refuses edits. A read-only field shows its model value on Android too, including a value that changes after mount. That fix is in @sigx/lynx-runtime 0.34.0, so it covers any model-bound read-only <input>, not only this component.

Props#

Input.Root#

PropTypeDefaultDescription
modelstring—Two-way binding of the text.
defaultValuestring''Initial text when uncontrolled.
type'text' | 'email' | 'password' | 'search' | 'tel' | 'url''text'The field type.
inputmode'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url'—Which keyboard to show. See the table above.
enterkeyhint'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'—What the Enter key says.
maxlengthnumber—Maximum length.
spellcheckbooleanplatform defaultSpell-checking, iOS.
autocorrect'on' | 'off'platform defaultAutocorrection, iOS.
autofocusbooleanfalseFocus the field on mount.
model:visibleboolean—Whether a password field shows its characters.
defaultVisiblebooleanfalseInitial visibility when uncontrolled.
disabledbooleanfalseORed with the Field's and the Fieldset's.
invalidbooleanfalseORed with the Field's and the Fieldset's.
requiredbooleanfalseORed with the Field's.
readonlybooleanfalseAnnounced and selectable, never edited. ORed with the Field's and the Fieldset's.
colorstringskin defaultThe focus accent.
sizestringskin defaultFalls back to the enclosing Field's size.
labelstring—Accessible name for the native field. The visible label is separate.
classstring—Extra classes, appended after the computed ones.

Parts#

PartProps
Input.LabelvisuallyHidden, class. A tap focuses the field.
Input.Controlclass. A tap on it focuses the field.
Input.Inputplaceholder, class. Emits focus, blur and confirm.
Input.Adornmentplacement ('start' | 'end', required), class.
Input.ClearTriggerlabel (default "Clear"), class, and a slot replacing ×.
Input.VisibilityTriggerlabel (default "Show password"), class, and a slot given { visible }.

Events#

EventPartPayloadDescription
valueChange (onValueChange)RootstringThe text changed.
visibleChange (onVisibleChange)RootbooleanPassword visibility changed.
focus (onFocus)Input—The native field gained focus.
blur (onBlur)Input—The native field lost focus.
confirm (onConfirm)InputstringThe keyboard's Enter key, with the text.

Anatomy on Lynx#

PartElementStatesFlags
rootview—disabled, invalid, required, readonly
labeltext—disabled, invalid, required
controlview—disabled, invalid, readonly, focus-visible
inputnative input—disabled, invalid, required, readonly, focus-visible
adornmentview—disabled
clear-triggerview (button trait)—disabled, pressed
visibility-triggerview (button trait)on | offdisabled, pressed

Not taken on Lynx: name and form (Lynx has no forms), Escape-to-clear (no hardware Escape key), modelModifiers timing, and validate / validateOn.

See also#