- Getting Started
- Architecture
- The Basics
- Digging Deeper
-
EDGE Components
- Introduction
- Activity Indicator
- Badge
- Bottom Navigation
- Bottom Sheet
- Button
- Button Group
- Canvas
- Carousel
- Checkbox
- Chip
- Column
- Divider
- Gesture Area
- Icon
- Image
- Lazy Grid
- Layout & Styling
- List
- Menus
- Modal
- Pressable
- Progress Bar
- Radio Group
- Refreshable
- Row
- Scroll View
- Select
- Shapes
- Side Navigation
- Slider
- Spacer
- Stack
- Tab Row
- Text
- Text Input
- Toggle
- Top Bar
- Virtual List
- Web View
- Plugins
- Testing
- Publishing Your App
Text Input
Get the Jump app
You'll need the free Jump app to preview this page on your device. Install it, then scan the code again.
Overview#
Native text input fields come in three variants:
<native:outlined-text-input>— bordered field. Default, lower emphasis.<native:filled-text-input>— surface-fill background + bottom indicator line. Higher emphasis.<native:bare-text-input>— chromeless field with no Material chrome, for chat pills, search bars, and inline editors where the surrounding container supplies the visuals. See Bare variant.
All three share the same prop set and event API. Choose the outlined / filled pair based on emphasis, not behavior; reach for bare when you want to style the input yourself.
On iOS the outlined and filled variants render as SwiftUI TextField / SecureField with Material3-style chrome; on
Android they map to OutlinedTextField / TextField (filled). Per Material 3 these two have no per-instance color or
border overrides — all chrome resolves from the theme. For fully custom input visuals reach for the bare variant, or
drop to <native:pressable> wrapping your own drawing.
@php $email = ''; @endphp <native:outlined-text-input label="Email" native:model="email" keyboard="email" leading-icon="email"/>
email is a public string property on your component — the @php line stands in for
public string $email = ''; and seeds the inline preview.
Props#
All three variants accept the same shared prop set. The bare variant adds a color attribute on top — see
Bare variant.
Content#
value- Current text value (optional, string)placeholder- Placeholder shown when empty (optional, string)label- Label rendered above the field (optional, string)supporting- Helper text rendered below the field (optional, string)
State#
disabled- Disable the input (optional, boolean, default:false)read-only- Make the input read-only (optional, boolean, default:false)is-error- Show error styling (border / indicator + supporting text turntheme.destructive)loading- Show a spinner in the trailing position (optional, boolean, default:false)
Behavior#
keyboard- Keyboard hint string:text(default),number,email,phone,url,decimal,password,numberPassword. On iOSpassworduses the standard keyboard;secureis the masking mechanismsecure- Mask input for passwords (optional, boolean, default:false)multiline- Allow multiple lines (optional, boolean, default:false)max-length- Maximum character count (optional, int)max-lines- Maximum visible lines whenmultiline(optional, int)min-lines- Minimum visible lines whenmultiline(optional, int)keep-focus-on-submit- Keep the keyboard up after@submitinstead of unfocusing the field on return — the chat "send and keep typing" pattern (optional, boolean, default:false)sync-mode- How change events dispatch back to your component:live(default),blur, ordebounce. Usually set via thenative:modelmodifiers below, but accepted directly toodebounce-ms- Milliseconds of inactivity before adebouncesync fires (optional, int, default:300)
Decorations#
prefix- Text rendered before the input (optional, string)suffix- Text rendered after the input (optional, string)leading-icon- Icon name rendered at the start (optional, string)trailing-icon- Icon name rendered at the end (optional, string)
Typography#
font- Custom font: aresources/fonts/file token or a config alias likeaccent(optional, string) — see Text › Custom fontsleading-*classes set line height for the typed text (multi-line only). Applies on Android; iOS inputs don't reflect it — SwiftUI's editable field ignores line spacing (it works on<native:text>)line-height/line-height-pxattributes are an alternative to theleading-*classes:line-heightis a multiplier of the font size,line-height-pxan absolute override
Sizing & accessibility#
size-sm | md (default) | lga11y-label- Accessibility label (optional)a11y-hint- Accessibility hint (optional)
Events#
@change- Component method called when the text changes. Receives the new value@submit- Component method called when the user submits (e.g. presses return). Receives the current value
Two-way Binding#
Use the native:model directive for automatic two-way binding with a component property. The directive expands to
:value, @change="__syncProperty(...)", and a sync-mode prop driven by the modifier chain.
@php $name = 'Ada'; $email = ''; $search = ''; @endphp <native:outlined-text-input label="Name" native:model="name" /><native:outlined-text-input label="Email" native:model.blur="email" /><native:outlined-text-input label="Search" native:model.debounce.500ms="search" /> <native:text class="text-sm text-theme-on-surface-variant">Hello, {{ $name }}!</native:text>
name, email, and search are public string properties on your component — typing syncs them back
automatically, so the {{ $name }} echo updates as you type.
sync-mode semantics:
live(default) — every keystroke fires@changeblur— only fires on focus loss / submitdebounce— fires afterdebounce-msof inactivity (300ms when unset), or immediately on blur / submit
Bare variant#
<native:bare-text-input> is a chromeless input — no outline, no fill, no label, no Material chrome, just the typing
affordance. It's built for chat input pills, search bars, and inline editors where the surrounding container provides
the visuals. On iOS it renders as a plain SwiftUI TextField; on Android as a Compose BasicTextField.
It inherits the full shared prop set — native:model, secure, multiline, keyboard, @submit,
keep-focus-on-submit, disabled, read-only, and the rest — so it behaves exactly like the other variants.
Two things set it apart:
- Class-based styling passes through. Unlike the filled / outlined variants (which resolve all chrome from the
theme), the bare variant lets element-level styling flow to the input directly:
bg,rounded-*, borders,glass, opacity, elevation, and padding. So you can style the pill on the input itself, no wrapping row needed. - A
colorattribute sets the text color — a hex value or a Tailwind token, withdark:text-*support for a light/dark pair. Useful when your wrapper overrides the background and the theme's default text color would vanish.
@php $draft = ''; @endphp <native:bare-text-input class="flex-1 glass rounded-full px-4 py-2 dark:text-slate-700" placeholder="Message" native:model="draft" @submit="send" keep-focus-on-submit/>
The color attribute can be set explicitly or picked up from a text-* class on the input:
@php $query = ''; @endphp <native:bare-text-input placeholder="Search" native:model="query" color="slate-700" /><native:bare-text-input placeholder="Search" native:model="query" class="text-slate-700 dark:text-slate-300" />
Examples#
Login form#
@php $email = ''; $password = ''; @endphp <native:column class="w-full gap-4 p-4"> <native:outlined-text-input label="Email" native:model="email" keyboard="email" leading-icon="email" /> <native:outlined-text-input label="Password" placeholder="Enter password" native:model="password" secure leading-icon="lock" /> <native:button label="Sign In" @press="login" /></native:column>
Filled variant with validation error#
@php $email = 'not-an-email'; @endphp <native:filled-text-input label="Email" native:model="email" is-error supporting="Please enter a valid email address"/>
Multiline textarea#
@php $message = ''; @endphp <native:outlined-text-input label="Message" placeholder="Type your message..." native:model="message" multiline :min-lines="3" :max-lines="8"/>
Search with submit#
@php $query = ''; @endphp <native:filled-text-input placeholder="Search..." native:model.debounce.300ms="query" @submit="submitSearch" leading-icon="search"/>
Prefix and suffix#
@php $price = '49'; @endphp <native:outlined-text-input label="Price" native:model="price" prefix="$" suffix=".00" keyboard="decimal"/>
Element#
use Nativephp\NativeUi\Elements\OutlinedTextInput;use Nativephp\NativeUi\Elements\FilledTextInput;use Nativephp\NativeUi\Elements\BareTextInput; OutlinedTextInput::make() ->label('Email') ->value($email) ->keyboard('email') ->leadingIcon('email') ->onChange('updateEmail');
All three elements share the same fluent API (defined on BaseTextInput):
value(string $text),placeholder(string $text),label(string $text),supporting(string $text)disabled(bool $value = true),readOnly(bool $value = true),error(bool $value = true),loading(bool $value = true)keyboard(string|int $type),secure(bool $value = true),maxLength(int $length)multiline(bool $value = true),maxLines(int $lines),minLines(int $lines)keepFocusOnSubmit(bool $value = true)- Keep the keyboard up after@submitprefix(string $text),suffix(string $text)leadingIcon(?string $name = null, IosSymbol|string|null $ios = null, AndroidSymbol|string|null $android = null)- pass a shared$name, or per-platform$ios/$androidsymbols for a different icon on each platformtrailingIcon(?string $name = null, IosSymbol|string|null $ios = null, AndroidSymbol|string|null $android = null)- same per-platform form asleadingIcon()size(string $value)-sm | md | lgfont(string $name)- Custom font (file token or config alias)a11yLabel(string $value),a11yHint(string $value)syncMode(string $mode),debounceMs(int $ms)onChange(string $method),onSubmit(string $method)
BareTextInput adds one method on top of the shared API:
color(string $color)- Text color as a hex value or Tailwind token (withdark:text-*support)
in no time