Input
Import
Section titled “Import”import { Input } from '@delightstack/components';Types are also available:
import type { InputType, InputOption } from '@delightstack/components';Basic Usage
Section titled “Basic Usage”View code
<Input label="Name" placeholder="Enter your name" required />Input Types
Section titled “Input Types”The type prop supports 13 input types:
| Type | Description |
|---|---|
'text' | Standard text input (default) |
'email' | Email with validation |
'password' | Hidden text with optional reveal toggle |
'url' | URL validation |
'tel' | Phone number |
'search' | Search with clear button |
'number' | Numeric with increment/decrement buttons |
'textarea' | Multi-line text |
'date' | Date picker |
'time' | Time picker |
'datetime-local' | Date and time picker |
'color' | Color picker |
'file' | File selection |
Examples
Section titled “Examples”Text Inputs
Section titled “Text Inputs”View code
<Input type="text" label="Username" placeholder="Enter username" /><Input type="email" label="Email" placeholder="you@example.com" /><Input type="url" label="Website" placeholder="https://example.com" /><Input type="tel" label="Phone" placeholder="(555) 555-5555" />Number Input
Section titled “Number Input”View code
<Input type="number" label="Quantity" min={0} max={100} step={5} />Date and Time
Section titled “Date and Time”Use date, time, and datetime-local for temporal values. The label always stays floated since these controls render their own value UI. Constrain the range with min/max.
View code
<Input type="date" label="Date" bind:value={date} /><Input type="time" label="Time" bind:value={time} /><Input type="datetime-local" label="Date & time" bind:value={when} />The color type pairs a live swatch with the selected hex value. Bind value to read the chosen colour.
View code
<Input type="color" label="Brand color" bind:value={color} />Use file for uploads. Add accept to restrict file types and multiple to allow several at once. Selected files appear as a removable preview list, and image files show a thumbnail.
View code
<Input type="file" label="Attachment" /><Input type="file" label="Photos" accept="image/*" multiple />Textarea
Section titled “Textarea”View code
<script> import { Input } from '@delightstack/components';
let bio = $state('');</script>
<Input type="textarea" label="Bio" bind:value={bio} rows={4} auto_resize maxlength={500} show_counter/>Password with Strength Indicator
Section titled “Password with Strength Indicator”View code
<Input type="password" label="Password" bind:value={password} show_toggle strength_indicator/>Masked Input
Section titled “Masked Input”Use mask to auto-format user input. # = digit, A = letter, * = any character.
View code
<Input label="Phone" mask="(###) ###-####" bind:value={phone} /><Input label="Card Number" mask="#### #### #### ####" bind:value={card} /><Input label="Expiry" mask="##/##" bind:value={expiry} />Autocomplete
Section titled “Autocomplete”Provide options for dropdown suggestions. Use onfilter for async loading.
View code
<script> import { Input } from '@delightstack/components';
const cities = [ { value: 'nyc', label: 'New York' }, { value: 'la', label: 'Los Angeles' }, { value: 'chi', label: 'Chicago' }, ];
let selectedCity = $state('');</script>
<Input label="City" options={cities} bind:value={selectedCity} />Async Autocomplete
Section titled “Async Autocomplete”View code
<Inputlabel="Search users"onfilter={async (query) => { const results = await searchUsers(query); return results.map(u => ({ value: u.id, label: u.name }));}}bind:value={selectedUser}/>Multiple / Chips Mode
Section titled “Multiple / Chips Mode”Enable multiple to collect an array of values as chips/tags.
View code
<script> import { Input } from '@delightstack/components';
let tags = $state<string[]>([]);</script>
<Input label="Tags" multiple bind:value={tags} placeholder="Add tags..." />Prefix and Suffix
Section titled “Prefix and Suffix”View code
<Input label="Price" prefix="$" suffix="USD" type="number" /><Input label="Website" prefix="https://" placeholder="example.com" />Disabled
Section titled “Disabled”View code
<Input label="Disabled input" placeholder="Cannot edit" disabled />Filled
Section titled “Filled”Inputs are transparent (outlined) by default so they sit cleanly on any surface. Set filled to paint a solid surface background behind the field.
View code
<Input label="Outlined (default)" placeholder="Transparent surface" /><Input label="Filled" placeholder="Solid surface" filled />View code
<Input size="0" label="Small (42px)" placeholder="Small" /><Input size="1" label="Default (48px)" placeholder="Default" /><Input size="2" label="Medium (54px)" placeholder="Medium" /><Input size="3" label="Large (60px)" placeholder="Large" />Error and Helper Text
Section titled “Error and Helper Text”View code
<Input label="Email" type="email" error="Please enter a valid email address" description="We'll never share your email"/>Skeleton Loading
Section titled “Skeleton Loading”View code
<Input label="Name" skeleton={loading} bind:value={name} />Field Validation
Section titled “Field Validation”Pass a parse function to validate the value — standalone, it runs when the input is blurred, and the thrown error’s message shows below the field. While errored, the input re-validates on every keystroke so the message clears the moment the value is fixed.
Database tables expose a ready-made parse (plus name, type, label, and constraint props) for every field, so a single spread wires it all up:
<script> import { Input } from '@delightstack/components'; import { personTable } from '$lib/schema';
let email = $state('');</script>
<Input {...personTable.form.field.email} bind:value={email} />Inside a <Form>, the parse function is registered with the form instead, which runs it alongside the form-level schema (the schema wins when both error). See the Working with Forms guide.
| Prop | Type | Default | Description |
|---|---|---|---|
type | InputType | 'text' | Input type |
value | string | number | boolean | string[] | File | File[] | null | - | Current value, bindable |
label | string | - | Floating label text |
placeholder | string | - | Placeholder text |
disabled | boolean | false | Disable input |
readonly | boolean | false | Read-only mode |
required | boolean | false | Mark as required |
name | string | - | Form field name. Inside a Form, registers the field; with no value prop the input becomes context-driven (reads/writes the form data — no bind:value needed) |
skeleton | boolean | false | Show skeleton loading state |
tooltip | string | - | Tooltip text on hover |
Validation
Section titled “Validation”| Prop | Type | Default | Description |
|---|---|---|---|
error | string | boolean | - | Error message or boolean error state |
parse | (value: unknown) => unknown | - | Validator that throws a user-showable error message. Standalone it runs on blur (re-running on change while errored); inside a Form it is registered with the form instead |
pattern | string | - | Regex pattern |
minlength | number | - | Minimum length |
maxlength | number | - | Maximum length |
min | number | string | - | Minimum value (number/date) |
max | number | string | - | Maximum value (number/date) |
step | number | - | Step value for number inputs |
Visual
Section titled “Visual”| Prop | Type | Default | Description |
|---|---|---|---|
size | '0' | '1' | '2' | '3' | '1' | Input size |
prefix | string | - | Text before input |
suffix | string | - | Text after input |
icon | Component | - | Leading icon component |
clearable | boolean | false | Show clear button |
show_counter | boolean | false | Show character count |
description | string | - | Description text below input |
dense | boolean | false | Tighter internal spacing |
comfortable | boolean | false | More internal spacing |
filled | boolean | false | Paint a solid surface background behind the control (vs the default transparent/outlined look) |
id | string | auto | Element ID |
class | string | '' | Additional CSS classes |
Autocomplete
Section titled “Autocomplete”| Prop | Type | Default | Description |
|---|---|---|---|
options | InputOption[] | - | Suggestion options for autocomplete dropdown |
onfilter | (query: string) => Promise<InputOption[]> | - | Async filter callback |
Multiple / Chips
Section titled “Multiple / Chips”| Prop | Type | Default | Description |
|---|---|---|---|
multiple | boolean | false | Enable chips/tags mode (value becomes string[]) |
Textarea
Section titled “Textarea”| Prop | Type | Default | Description |
|---|---|---|---|
rows | number | 3 | Initial rows for textarea |
auto_resize | boolean | false | Auto-grow textarea to fit content |
Password
Section titled “Password”| Prop | Type | Default | Description |
|---|---|---|---|
show_toggle | boolean | false | Show password visibility toggle |
strength_indicator | boolean | false | Show password strength meter |
| Prop | Type | Default | Description |
|---|---|---|---|
mask | string | - | Input mask pattern (#=digit, A=letter, *=any) |
| Prop | Type | Default | Description |
|---|---|---|---|
accept | string | - | Accepted file types |
Events
Section titled “Events”| Event | Detail | Description |
|---|---|---|
oninput | { value } | Value is changing (during typing) |
onchange | { value } | Value is committed (on blur or selection) |
onfocus | - | Input focused |
onblur | - | Input blurred |
type InputType = | 'text' | 'email' | 'password' | 'url' | 'tel' | 'search' | 'number' | 'textarea' | 'date' | 'time' | 'datetime-local' | 'color' | 'file';
interface InputOption { value: string; label: string; disabled?: boolean; description?: string;}Accessibility
Section titled “Accessibility”- Proper
<label>association viafor/id - Error linked with
aria-describedby aria-requiredwhen requiredaria-invalidon error state- Full keyboard support for all modes
- Autocomplete: screen reader announces result count, keyboard navigation with arrow keys
- Focus ring visible on
:focus-visible