Input Policy
Native input intent first. Actual's runtime filters values only when explicitly asked, and fixed-shape masks stay opt-in through `data-mask`.
inputmode changes the virtual keyboard but does not constrain the value. Actual does not filter plain inputmode fields by default because numeric entry often needs temporary, signed, grouped, or locale-specific values while the user types. When the JavaScript runtime is loaded, Actual enhances input[data-filter]. Textareas are left alone. Add an explicit data-filter value when the field should enforce one of Actual's small built-in filters. Unsupported filter names are ignored. An empty data-filter never filters — inputmode is not read as a fallback, even when it is numeric or decimal. data-filter="numeric" / data-filter="decimal" are intentionally destructive (they rewrite the value as the user types), unlike inputmode, which only hints the virtual keyboard.
<label class="field">
<span class="field-label">Quantity</span>
<input class="input" inputmode="numeric" data-filter="numeric" placeholder="42" />
</label>
<label class="field">
<span class="field-label">Amount</span>
<input class="input" inputmode="decimal" data-filter="decimal" placeholder="12.34" />
</label>
Built-in filters
The built-in filters are intentionally narrow. They are input helpers, not domain validation.
numeric— Keeps ASCII digits only:0through9.decimal— Converts,to., keeps ASCII digits, and keeps the first.separator.lower— Converts the value withtoLocaleLowerCase().upper— Converts the value withtoLocaleUpperCase().letters— Keeps Unicode letters only. Digits, punctuation, symbols, and spaces are removed.slug— Normalizes accents, lowercases text, turns runs of non-letter and non-digit characters into-, collapses repeated-, and trims edge separators.
During direct typing, slug may keep a trailing - until the next character so words do not merge while the user is still entering text. Filters can be piped with | when a field needs more than one transform. They run from left to right.
<label class="field">
<span class="field-label">Slug</span>
<input class="input" data-filter="lower|slug" autocomplete="off" placeholder="release-notes" />
</label>
<label class="field">
<span class="field-label">Code</span>
<input class="input" data-filter="upper|letters" autocomplete="off" placeholder="ABC" />
</label>
For signed numbers, locale formatting, currency rules, time ranges, or app-specific character policies, use application code. Those rules are domain policy, not a framework default. See JavaScript for custom filter patterns built on enhance().
Pattern mask
Use data-mask when the input has a fixed shape. Tokens are 9 for a digit, a for a letter, and * for any character.
<label class="field">
<span class="field-label">Reference</span>
<input class="input" data-mask="aaa-999" autocomplete="off" placeholder="abc-123" />
</label>
<label class="field">
<span class="field-label">Date</span>
<input class="input" data-mask="9999-99-99" inputmode="numeric" autocomplete="off" placeholder="yyyy-mm-dd" />
</label>
Masks enforce shape, not domain validity. Use application validation when a date must reject impossible values such as 2026-13-40.