Text input#
Component <neo-textinput> is a wrapper around a native <input> with live formatting: mask, format="number", and composable transforms like numeric-only and case="upper". Reach for it when the displayed value should differ from the typed one; a bare <input> is the right answer otherwise. The native field lives in the element's shadow root, so the light DOM stays empty and a server can re-render the host without disturbing the live field. Slot <neo-option> children to add server-driven autocomplete suggestions with built-in keyboard navigation.
The selected state's markup and its scoped CSS. The CSS is wrapped in <style>@scope { ... }</style> and applies to the preview only. Edits change the preview above, applied live while Sync is on, or when you click Patch or Replace. Patch morphs the preview; Replace swaps it outright.
Signals
Datastar signals declared in the selected state's markup. Change a value to drive the preview, applied live while Sync is on, or when you click Patch.
Reference#
Attributes #
| Name | Type | Default | Description |
|---|---|---|---|
name | string | none | Form field name. |
type | string | "text" | Standard <input> type. |
value | string | none | Current value. For format="number", reads and writes the canonical numeric string (sign + digits + .); thousands separators and the localized decimal mark are presentation only. |
placeholder | string | none | Hint text shown when empty. |
disabled | boolean | false | Non-interactive state. |
readonly | boolean | false | Value cannot be edited but stays focusable and submittable. |
required | boolean | false | Form validation requires a non-empty value. |
size | "sm" | "lg" | none | Control-size step: sm compact, lg large. Omit for the default size. |
mask | string | none | Static template: # digit, U letter→upper, l letter→lower, A alnum→upper, a alnum→lower, X alnum (case preserved), * any char. Other chars are literal. Cased slots accept either case and coerce on insert. |
format | "number" | none | Right-anchored thousands grouping for numeric input. |
prefix | string | none | Leading literal preserved across clears. |
decimal-places | number | -1 | Decimal-place cap for format="number"; -1 unbounded. |
decimal-mark | "." | "," | "." | Decimal separator character. |
thousands-separator | string | "," | Grouping separator inserted every three digits. |
numeric-only | boolean | false | Drop non-digit input. |
case | "upper" | "lower" | "" | Force the displayed value to the given case. Free-form only; ignored when mask is set; use cased mask letters (U, A, l, a) instead. An unsupported value is ignored with a console warning. |
submit-raw | boolean | false | Form submission uses the unformatted value. Always on for format="number"; thousands separators never appear in the submitted value. |
open | boolean | false | Suggestions popover state using the shared command contract: open="true" opens, open="false" closes, and an omitted attribute leaves client state unchanged. Client-open state is reflected as bare open, so a fat morph that omits the attribute does not close the popover. |
placement | string | "bottom-start" | Suggestion popover placement relative to the field. The popover honors the same positioning surface as <neo-select> (placement, screen-offset, follow-scroll, clamp-placement, min-fit-height/min-fit-width, min-open-height/min-open-width, popover-fit-content) plus the --neo-popover-* custom properties. Applies only when the suggestions slot is in use. |
popover-fit-content | boolean | false | The suggestions panel tracks the field width by default; set this to size the panel to the suggestion rows instead. Capped by --neo-popover-max-width and the viewport. Applies only when the suggestions slot is in use. |
list | string | none | References a shared <neo-datalist> by its id (like native <input list>) to source the autocomplete suggestions. Inline suggestion options take precedence. |
Slots #
| Name | Description |
|---|---|
suggestions | Slotted <neo-option> children turn the field into an autocomplete: a listbox of suggestions. The field stays free text: the value is whatever's typed; options are hints. Bare <neo-option> children are assigned to this slot automatically. Same option API as <neo-select> (value, label, disabled, rich content). A [data-neo-empty-results] child is a non-selectable status row that keeps the popover open with zero options (same contract as <neo-combobox>). The server may patch the slot at any time; patching it empty (no options and no status row) closes the popover. The field gains role="combobox" whenever suggestions exist or the popover is open; focus never leaves it (ArrowDown/Up move aria-activedescendant). Alternatively, set list to source these options from a shared datalist. |
Events #
| Name | Detail | Bubbles | Description |
|---|---|---|---|
input | none | yes | Standard input event. |
change | none | yes | Standard change event. |
neo-textinput-input | { value: string, rawValue: string } | yes | Mirrors input with both formatted and raw values in detail. |
neo-textinput-change | { value: string, rawValue: string } | yes | Mirrors change. |
neo-textinput-select | { value: string, label: string } | yes | A suggestion was committed (click or Enter). value is the option's value, label its visible text. |
Examples#
Card-style mask#
In mask, # is a digit slot and the spaces between groups are literal delimiters.
- Spaces appear at the right positions as you type.
- Backspace at a delimiter deletes the preceding digit, so the literal never has to be skipped manually.
Mixed mask#
A mask can mix letter, digit, and literal slots. Cased slots (U, l, A, a) accept either case and coerce on insert; use X to keep the typed case.
Phone#
Parentheses, space, and dash are all literals in the mask.
Date#
A ##/##/#### mask shapes the digits but doesn't validate calendar logic (Feb 30 is accepted); pair it with the native pattern attribute when stricter checks are needed.
Number#
format="number" applies right-anchored thousands grouping with optional decimals. The prefix attribute pins a literal at the start.
Number (EU)#
European notation from the same number format: decimal-mark="," with a period thousands-separator.
Disabled#
disabled and readonly pass through to the inner field: disabled fades the host and blocks all interaction; readonly leaves the value selectable but immutable.
Examples: Datastar#
Suggestion states#
Slotted suggestions are server state: a Datastar morph can swap the set at any time and the field reconciles in place. Switch states to compare.
- Initial has no suggestions; Suggestions, Disabled, and Rich morph rows in: plain, with
disabledrows, then rich rows (icon plus a short description). The typed value is untouched. - No results shows a non-selectable
[data-neo-empty-results]status row, keeping the popover open with zero options instead of closing. - The
openattribute forces the popover open so each state shows without focusing the preview; normally suggestions appear on focus.
The selected state's markup and its scoped CSS. The CSS is wrapped in <style>@scope { ... }</style> and applies to the preview only. Edits change the preview above, applied live while Sync is on, or when you click Patch or Replace. Patch morphs the preview; Replace swaps it outright.
Signals
Datastar signals declared in the selected state's markup. Change a value to drive the preview, applied live while Sync is on, or when you click Patch.
Autocomplete#
Slot <neo-option> children to turn the field into an autocomplete: free text the user can submit as typed, with server-supplied suggestions and built-in keyboard navigation.
- Each debounced keystroke posts the query; the server morphs matching
<neo-option>rows into thesuggestionsslot, a[data-neo-empty-results]row when nothing matches, or nothing to close the popover. - Focus stays in the field; ArrowDown / ArrowUp move the highlight, Enter or click fills it, Escape closes. Options keep the
<neo-option>API:value,label,disabled, rich content. - Constrain the value to a fixed set instead? Combobox is the constrained-selection version.
Loading states only show with simulated delay. Raise network latency or handler delay in the Settings panel.