Text & number input

AppInput

The single-line text field — name, email, amount — with label, hint, error, and optional icon, unit, and password reveal.

<app-input label="Email" name="email" type="email" />

<app-input> is the shared single-line field, and the one you'll reach for most. It handles any short text or numeric value — a name, an email, an amount, a reference — with a consistent label, hint, and error treatment, so every field in a form reads the same.

Its look comes entirely from the shared @webority/theme, so the Razor <app-input> and the React <AppInput> render identically — a field is a field on every Webority surface.

Playground

Every meaningful attribute, live. Each change re-renders the real tag helper on the server, so the markup underneath is the exact call that produced the field above it.

<app-input label="Email" name="pg-input" placeholder="you@company.com" />
Shells are mutually exclusivefloating-label, prefix/suffix, unit, password (type="password"), right-icon and clearable each render their own control shell — set more than one and the field falls back to a fixed precedence (floating-label → affix → unit → password → right-icon → clearable → left-icon). A leading icon is the exception: it pairs with the password and clearable shells.

Trailing action

A control beside the field, outside its border — a labelled button (verify, apply, send code), or a confirmation once the value resolves. The field flexes to fill the row; the action keeps its natural width. Compose it with an <app-input-action> child; it pairs with a leading icon and is exclusive with the in-field shells.

A verify button, and the confirmation it becomes
Verified
Show code
<app-input label="PAN" name="pan" placeholder="Enter PAN">
  <app-input-action><app-button variant="secondary">Verify</app-button></app-input-action>
</app-input>
<app-input label="PAN" name="pan" value="ABCDE1234F">
  <app-input-action><app-button variant="success" static="true" left-icon="check-circle">Verified</app-button></app-input-action>
</app-input>

Types

The type sets the on-screen keyboard and native validation — email, number, tel, and more. The field looks the same; the input behaviour follows the type.

Common input types
Show code
<app-input label="Email" name="email" type="email" placeholder="you@company.com" />
<app-input label="Area" name="area" type="number" placeholder="0" />
<app-input label="Phone" name="phone" type="tel" placeholder="+91 98765 43210" />

Without a label

The label is optional — omit it for a compact, placeholder-only field like a toolbar search or a filter. Give it an aria-label so it still has an accessible name.

Placeholder only
Show code
<app-input name="q" aria-label="Search" left-icon="search" placeholder="Search projects…" />
A placeholder is not a labelPlaceholder text vanishes on typing and isn't a reliable accessible name. With no visible label, set aria-label so screen readers still announce the field's purpose.

Floating label

An animated variant: the label starts inside as the placeholder, then slides up and shrinks on focus or once the field is filled. Set floating-label — it's standalone (no icon/unit/affix in the same field).

Label that slides up
Show code
<app-input label="Email address" name="email" type="email" floating-label="true" />
A per-field opt-in, not the defaultThe system's default is a static label above the field. Reach for floating-label on compact forms — and keep it consistent within a form, don't mix floating and static.

Sizes

Three sizes. Default (md) suits almost everything; use sm inside dense toolbars and filter bars, lg for a marketing-scale field.

sm · md · lg
Show code
<app-input label="Small" name="s" size="sm" placeholder="sm" />
<app-input label="Medium" name="m" placeholder="md (default)" />
<app-input label="Large" name="l" size="lg" placeholder="lg" />

Leading icon

A leading icon drops a glyph inside the start of the field — a mail icon on an email, a person on a name — to make the field's purpose scannable at a glance.

A field with a leading icon
Show code
<app-input label="Email" name="email" type="email" left-icon="mail" placeholder="you@company.com" />

Unit suffix

A unit suffix prints a fixed label inside the field — a measurement, a currency, a percentage — without it becoming part of the typed value.

A numeric field with a unit
m²
Show code
<app-input label="Area" name="area" type="number" unit="m²" placeholder="0" />

Prefix & suffix

A bordered box attached before or after the input — a currency mark, a URL scheme, a domain suffix. Use it when the affix is a fixed, non-editable part of the value's shape.

A prefix and a suffix
₹.00
https://.com
Show code
<app-input label="Amount" name="amt" type="number" prefix="₹" suffix=".00" />
<app-input label="Site" name="site" prefix="https://" suffix=".com" />

Clearable

Set clearable and an ✕ appears once the field has a value — one click empties it and refocuses. Useful on any editable field: a coupon, a tag, a filter value. (For an actual search box, reach for AppSearch.) The ✕ fades in as you type.

An ✕ to reset the field
Show code
<app-input label="Coupon code" name="coupon" clearable="true" placeholder="Enter a code" />

Character count

Set show-count for a live count under the field; add max-length to cap the input and show the denominator. The count turns red at the limit.

Live count with a cap
22 / 60
Show code
<app-input label="Headline" name="headline" show-count="true" max-length="60" placeholder="Up to 60 characters" />

Password

A password field can show a reveal toggle — an eye button the user taps to check what they typed before submitting.

Password with reveal
Show code
<app-input label="Password" name="password" type="password" placeholder="••••••••" />
Password with a leading icon
A leading icon pairs with the reveal toggle, just like any other field.
Show code
<app-input label="Password" name="password" type="password" left-icon="lock" placeholder="••••••••" />
Live requirements checklist
Add password-requirements to show a checklist on focus that ticks each rule green as the user types — client-side, before any server round-trip. requirements-placement (auto | top | bottom | start | end) chooses the side. Focus the field to try it.
Show code
<app-input label="New password" name="new-password" type="password" password-requirements requirements-placement="auto" placeholder="••••••••" />
A configured policy, opening to the right
Individual attributes override the default rules — here a 10-character minimum plus a unique-characters rule, a custom title, opened to the end (right) side.
Show code
<app-input label="New password" name="pw-policy" type="password" password-requirements password-min-length="10" password-unique-chars="4" requirements-title="Choose a strong password" requirements-placement="end" placeholder="••••••••" />
Let users see what they typedThe reveal toggle cuts sign-in and sign-up errors — a masked field hides typos the user can't catch. Turn it on for any password field so users can double-check before they submit. The requirements checklist is a client-side hint, not the security control — the server still validates; the rule set is shared with React via @webority/ui-elements so both surfaces validate identically.

Validation

Show a hint for guidance and an error when validation fails. They share one slot below the field — the error replaces the hint and turns the field red. Mark required fields on the label.

Hint, error, and required
15-character GST identification number.
Enter a valid email address.
Show code
<app-input label="GSTIN" name="gstin" hint="15-character GST identification number." />
<app-input label="Email" name="email" required error="Enter a valid email address." />
Make the error say how to fix ithint and error occupy the same line, so a set error hides the hint. Write the error as an instruction — "Enter a valid email address" — not just "Invalid".

Disabled

Set disabled when a field can't be edited yet — it depends on an earlier choice, or the value is fixed. The control greys out, stops taking focus, and is skipped on submit.

A disabled field
Show code
<app-input label="Workspace" name="workspace" value="Acme Inc." disabled="true" />
<app-input label="Plan" name="plan" value="Enterprise" left-icon="briefcase" disabled="true" />
Disabled vs read-onlydisabled greys the field and drops it from the form submission. If the value should still submit but not be editable, use a read-only control instead.

Custom class

Hook your own styling onto a field: input-class lands on the input element, a plain class on the .field wrapper. Both append after the design-system classes, so yours win on equal specificity.

A class on the input and the wrapper
Show code
<app-input label="Email" name="email" input-class="js-track" class="grid-col-span-2" />

When to use

Use it when

  • The user enters a single line of text or a number — name, email, amount, reference.
  • You want the shared field treatment: label, hint, error, and required marking.
  • A specific type (email, number, tel) should drive the keyboard and native validation.

Reach for something else when

  • The value runs to multiple lines — a note or description. → AppTextarea
  • The user picks from a fixed set of options. → AppSelect
  • It is a search box that filters a list. → AppSearch
  • The value is a calendar date. → AppDatePicker

Best practices

Do
A visible label stays put while the user types and is read by screen readers.
Don't
A placeholder used as the label vanishes on the first keystroke and fails accessibility.
Do
type="email" brings the right keyboard and native validation for free.
Don't
A plain text type misses the email keyboard and validation the browser could give.
Do
Enter a valid email address.
A specific error tells the user exactly what to change.
Don't
Invalid
'Invalid' leaves them guessing what is actually wrong.

Every option

The whole surface of the component, one cell per value — every input type, every shell, and the combinations that behave specially.

type — all seven

type="text"
type="email"
type="number"
type="tel"
type="url"
type="search"
type="password"

size — every size

size="sm"
size="md"
size="lg"

state

(default)
required
disabled
error="…"
Required
hint="…"
A hint
required + error
Required

icon slots

left-icon="mail"
right-icon (no click handler in Razor — always disabled)
right-icon-label="Run search"
left-icon + clearable
onRightIconClick is React-onlyRazor's right-icon has no server-side click handler — the trailing-icon button is always rendered disabled, unlike React where passing onRightIconClick enables it.

unit & affixes

unit="m²"
m²
prefix="₹"
₹
suffix=".com"
.com
prefix + suffix
₹.00

floating-label

floating-label (empty)
floating-label + value
floating-label + required

variant

variant="bare"

clearable

clearable, empty (✕ hidden)
clearable + value (✕ visible)
clearable + disabled (✕ never shown)

show-count

show-count, no max-length
0
show-count + max-length (under limit)
22 / 60
show-count + max-length (at limit, red)
4 / 4

password

type="password"
type="password" + left-icon
password-requirements (focus me)

edge cases

long content overflows the fixed-width field
no label, aria-label only

Attributes

AttributeTypeDefaultDescription
asp-forModelExpression—Razor-only; no React equivalent. Binds to a Razor Pages model property — derives name, id, value, [Display] label and [Required], and emits unobtrusive validation attributes plus the validation message in place of a manual error.
labelstring—The field label. Always set one — never rely on the placeholder.
namestring—Field name; also used as the id.
typestringtextNative input type — text, email, number, tel, password, etc.
prefixstring—A bordered box before the input (e.g. https://).
suffixstring—A bordered box after the input (e.g. .00).
floating-labelbool—Label sits inside as a placeholder, then slides up once the field has focus or a value.
clearablebool—Show an ✕ button while the field has a value.
show-countbool—Show a live count / max-length under the field.
max-lengthint—Character cap; the count turns red as it is approached.
sizesm | lgmdControl size. Omit for the default (md).
placeholderstring—Placeholder text shown while the field is empty.
valuestring—Pre-filled value of the field.
requiredboolfalseAppends a required mark to the label.
hintstring—Helper text below the field. Hidden while an error is shown.
errorstring—Error message. Turns the field red and replaces the hint.
left-iconstring—Bootstrap Icons glyph shown inside the start of the field.
unitstring—Fixed suffix printed inside the field (e.g. m², %).
right-iconstring—Bootstrap Icons glyph for a trailing icon (React rightIcon).
right-icon-labelstring—Accessible name for the right-icon button. Defaults to the icon name, which is a poor label but not an absent one.
disabledbool—Disable the control.
helpstring—Info-tip content shown beside the label (React help).
help-labelstringMore informationaria-label for the info-tip button (React helpLabel).
idstring—Explicit control id. Defaults to name (React id).
input-classstring—Extra classes on the input element (React className).
classstring—Extra classes on the .field wrapper (React fieldClassName).
variantbare—Borderless variant — no border/background, inherits the container's chrome (inline-rename, ⌘K). Matches React variant.
password-requirementsboolfalseOnly honoured on type="password". Shows a live requirements checklist popover on focus that ticks each rule green as the user types — client-side, before server validation. The rule set is shared with React via @webority/ui-elements. Maps to React passwordRequirements.
password-min-lengthint8Minimum-length rule. Set 0 to drop the length rule.
password-uppercasebooltrueRequire at least one uppercase letter.
password-lowercasebooltrueRequire at least one lowercase letter.
password-digitbooltrueRequire at least one digit.
password-specialbooltrueRequire at least one special (non-alphanumeric) character.
password-unique-charsint0Require at least N distinct characters. 0 omits the rule.
requirements-titlestringPassword RequirementsHeading shown at the top of the requirements popover. Maps to React passwordRequirements.title.
requirements-placementauto | top | bottom | start | endautoWhich side the requirements popover opens; auto flips to stay in view. Matches React requirementsPlacement.