elements
Demos UI Feed Discuss Install
Style System
  • Style
  • Themes
  • Behaviors
Forms
  • Button
  • ButtonGroup
  • Checkbox
  • ColorPicker
  • Combobox
  • Field
  • FileUpload
  • Input
  • InputGroup
  • InputOTP
  • Label
  • NativeSelect
  • NumberInput
  • PasswordInput
  • RadioGroup
  • Select
  • Slider
  • Switch
  • TagsInput
  • Textarea
  • Toggle
  • ToggleGroup
Overlays
  • AlertDialog
  • Command
  • ContextMenu
  • Dialog
  • Drawer
  • DropdownMenu
  • HoverCard
  • Menubar
  • NavigationMenu
  • Popover
  • Sheet
  • Toast
  • Tooltip
Display
  • Accordion
  • Alert
  • AspectRatio
  • Avatar
  • Badge
  • Breadcrumb
  • Card
  • Collapsible
  • Empty
  • Item
  • Kbd
  • Pagination
  • Progress
  • Separator
  • Skeleton
  • Spinner
  • Table
  • Tabs
  • Tree
Layout
  • Carousel
  • Resizable
  • ScrollArea
  • Sidebar
Dates
  • Calendar
  • DatePicker
  • DateRangePicker
  • TimePicker
Data
  • AreaChart
  • BarChart
  • Chart
  • DataTable
  • Kanban
  • LineChart
  • PieChart
  • RadarChart
  • RadialChart
  • VirtualList
Chat
  • Attachment
  • Message
  • MessageList
  • PromptInput
Elements UI / Forms / Input

Input

A native text input in the theme's control chrome, with a two-way value.

Basic

value is two-way: type here and the state below follows.

value: Ada input events: 0
Code
<Label htmlFor="name">Name</Label>
<Input value={state.name} attrs={{ id: "name" }} />

Usage

import { Input } from "@elements/ui/input";

<Input value={form.email} type="email" placeholder="you@example.com" />
<Input value={form.name} invalid={!!form.error} size="sm" />
<Input type="file" multiple files={form.photos} attrs={{ accept: "image/*" }} />

Examples

Value change

onValueChange gets the new value and details before the value changes; details.cancel() keeps the old one. This one takes digits only.

value: last change: none yet
Code
<Input value={state.pin} attrs={{ inputmode: "numeric" }} onValueChange={(v, d) => digitsOnly(state, v, d)} />

function digitsOnly(state: State, value: string, details: ChangeDetails): void {
  if (/\D/.test(value)) {
    details.cancel();
  }
}

API key

A read only value with a description and a Copy button beside it. The label swaps in place.

Keep it secret. Rotate it if it leaks.

Code
<Label htmlFor="api-key">API Key</Label>
<div class="row">
  <Input value="sk_live_51H8x2eKq9" readonly attrs={{ id: "api-key", "aria-describedby": "api-key-hint" }} />
  <Button onclick={() => copy(state)}>
    <span class="swap-label" data-state={state.copied ? "on" : "off"}>
      <span class="swap-off">Copy</span><span class="swap-on">Copied</span>
    </span>
  </Button>
</div>
<p class="hint" id="api-key-hint">Keep it secret. Rotate it if it leaks.</p>

Types

The native type drives the keyboard, the picker and validation.

Code
<Input type="email" placeholder="you@example.com" />
<Input type="password" placeholder="Password" />
<Input type="number" placeholder="Quantity" />
<Input type="search" placeholder="Search" />
<Input type="date" />

Sizes

Heights come from the theme's control tokens.

Code
<Input size="sm" placeholder="Small" />
<Input placeholder="Medium" />
<Input size="lg" placeholder="Large" />

Disabled, read only, invalid

States change color, never size.

Code
<Input disabled value="Disabled" />
<Input readonly value="Read only" />
<Input invalid value="not-an-email" />

File

type=file binds the picked files; the picker button follows the theme.

files: none
Code
<Input type="file" multiple files={state.photos} attrs={{ accept: "image/*" }} />

Inline with a button

A required search: an empty submit is blocked by the browser.

submitted: 0
Code
<form onsubmit={() => search(state)}>
  <Input type="search" name="q" value={state.search} placeholder="Search" required />
  <Button type="submit" variant="primary">Search</Button>
</form>

Required

Inside a Field, required adds the asterisk and the browser's check.

The asterisk marks it; the browser blocks an empty submit.

Code
<Field label="Username" required description="The asterisk marks it; the browser blocks an empty submit.">
  <Input value={state.username} />
</Field>

Badge

A FieldLabel part takes a Badge beside the text.

Code
<Field>
  <FieldLabel>Webhook URL{" "}<Badge variant="outline">Beta</Badge></FieldLabel>
  <Input type="url" value={state.webhook} placeholder="https://api.example.com/webhook" />
</Field>

Field group form

Fields in a FieldGroup; the form validates each one natively.

sent: 0
Code
<form onsubmit={() => send(state)}>
  <FieldGroup>
    <Field label="Name"><Input value={state.name} autocomplete="name" /></Field>
    <Field label="Email" required><Input type="email" value={state.email} /></Field>
    <Button type="submit" variant="primary">Submit</Button>
  </FieldGroup>
</form>

Form

Name, email, phone, country and address in one form; Cancel resets it.

We'll never share your email with anyone.

United States
United Kingdom
Canada
sent: nothing
Code
<form onsubmit={() => send(contact)}>
  <FieldGroup>
    <Field label="Name"><Input value={contact.name} placeholder="Jane Doe" /></Field>
    <Field label="Email" description="We'll never share your email with anyone.">
      <Input type="email" value={contact.email} placeholder="john@example.com" />
    </Field>
    <div class="grid">
      <Field label="Phone"><Input type="tel" value={contact.phone} placeholder="+1 (555) 123-4567" /></Field>
      <Field label="Country">
        <Select value={contact.country} items={COUNTRIES} placeholder="Select a country" block />
      </Field>
    </div>
    <Field label="Address"><Input value={contact.address} placeholder="123 Main St" /></Field>
    <div class="actions">
      <Button type="reset">Cancel</Button>
      <Button type="submit" variant="primary">Submit</Button>
    </div>
  </FieldGroup>
</form>

Input group and button group

An Input takes addons in an InputGroup, or joins buttons in a ButtonGroup.

Code
<InputGroup>
  <InputGroupAddon><Icon name="search" /></InputGroupAddon>
  <Input value={state.query} placeholder="Search" />
</InputGroup>

<ButtonGroup>
  <Input value={state.url} placeholder="https://" />
  <Button>Go</Button>
</ButtonGroup>

Grid

Inputs fill their cell; two columns collapse to one on a phone.

Code
<Label htmlFor="first">First name</Label>
<Input attrs={{ id: "first" }} />
<Label htmlFor="last">Last name</Label>
<Input attrs={{ id: "last" }} />

Right to left

Text, placeholder and the file button follow the inline direction.

Reference Input in the manual Every part, attribute, slot, key and data attribute.
Prev FileUploadNext InputGroup
Product
Manual Pricing Compare
Company
History Contact
Legal
Privacy Policy Acceptable Use Terms License Agreement
© Elements Dev Corporation 2026