Input
Capture user text input with a flexible, accessible field. Supports variants, colors, icons, avatars, loading, highlight, and custom snippets.
leadingSlot and trailingSlot now reserve room in the field, so their content no longer sits on top of the text, and pointer events
reach them, so a button in a slot is clickable. A decorative leadingIcon or trailingIcon stays click through, slot content is inert while the field is disabled or loading, and the loading
spinner takes precedence over a slot rather than being swallowed by it.Playground
Experiment with different props in real-time.
Basic Usage
A simple text input.
<script lang="ts">
import { Input } from 'sv5ui';
</script>
<Input placeholder="Enter text..." />Variants
5 visual styles.
<Input variant="outline" placeholder="Outline" />
<Input variant="soft" placeholder="Soft" />
<Input variant="subtle" placeholder="Subtle" />
<Input variant="ghost" placeholder="Ghost" />
<Input variant="none" placeholder="None" />Sizes
5 sizes.
<Input size="xs" placeholder="Extra Small" />
<Input size="sm" placeholder="Small" />
<Input size="md" placeholder="Medium" />
<Input size="lg" placeholder="Large" />
<Input size="xl" placeholder="Extra Large" />Colors
Color schemes visible when highlight is active.
<Input color="primary" highlight placeholder="Primary" />
<Input color="secondary" highlight placeholder="Secondary" />
<Input color="success" highlight placeholder="Success" />
<Input color="warning" highlight placeholder="Warning" />
<Input color="error" highlight placeholder="Error" />
<Input color="info" highlight placeholder="Info" />With Icons
Add icons in various positions.
<!-- Leading icon (shorthand) -->
<Input icon="lucide:search" placeholder="Search..." />
<!-- Leading icon (explicit) -->
<Input leadingIcon="lucide:mail" placeholder="Email" />
<!-- Trailing icon -->
<Input trailingIcon="lucide:eye" placeholder="Password" type="password" />
<!-- Both icons -->
<Input leadingIcon="lucide:link" trailingIcon="lucide:copy" placeholder="https://example.com" />
<!-- Trailing prop: moves icon to right -->
<Input icon="lucide:calendar" trailing placeholder="Pick a date" />With Avatar
Display an avatar in the leading position.
<Input
avatar={{ src: 'https://i.pravatar.cc/40', alt: 'User' }}
placeholder="What's on your mind?"
/>Input Types
All HTML input types are supported.
<Input type="text" placeholder="Text" />
<Input type="password" placeholder="Password" trailingIcon="lucide:eye" />
<Input type="number" placeholder="Number" />
<Input type="email" placeholder="Email address" leadingIcon="lucide:mail" />
<Input type="url" placeholder="https://..." leadingIcon="lucide:globe" />
<Input type="tel" placeholder="Phone number" leadingIcon="lucide:phone" />Loading
Show a spinner.
<Input loading placeholder="Loading..." />
<Input loading leadingIcon="lucide:search" placeholder="Searching..." />Highlight
Show a colored ring. Auto-enabled on form errors.
<!-- Normal highlight -->
<Input highlight placeholder="Highlighted input" />
<!-- Error highlight -->
<Input highlight color="error" placeholder="Error highlight" />
<!-- Success highlight -->
<Input highlight color="success" placeholder="Success highlight" />Disabled
Prevent interaction.
<Input disabled placeholder="Disabled input" />
<Input disabled value="Cannot edit this" />Controlled
Use bind:value for two-way binding.
You typed: (empty)
<script lang="ts">
import { Input } from 'sv5ui';
let value = $state('');
</script>
<Input bind:value placeholder="Type something..." />
<p>You typed: {value}</p>UI Slots
Use the ui prop to override classes on internal elements.
| Slot | Description |
|---|---|
root | Outermost wrapper - controls overall layout |
base | Inner input element - controls shape, padding, typography |
leading | Leading content wrapper |
leadingIcon | Icon before input |
leadingAvatar | Avatar before input |
leadingAvatarSize | Avatar size override |
trailing | Trailing content wrapper |
trailingIcon | Icon after input |
<Input
placeholder="Custom styled"
leadingIcon="lucide:search"
ui={{
root: 'rounded-full',
base: 'rounded-full',
leadingIcon: 'text-primary'
}}
/>Snippets
Replace the leading or trailing content. The field reserves room for a snippet and lets the pointer reach it, so a button in one works; an override is only needed for content wider than the space an icon would take, like the prefix below.
| Snippet | Description |
|---|---|
leadingSlot | Custom content before input - replaces icon and avatar |
trailingSlot | Custom content after input - replaces trailing icon |
<!-- The field reserves room for a snippet on its own; ps-18 is here only because
the https:// prefix is wider than the space an icon would need. -->
<Input placeholder="example.com" ui={{ base: 'ps-18' }}>
{#snippet leadingSlot()}
<span class="border-r border-on-surface/15 pr-2 text-xs font-medium text-on-surface/50">https://</span>
{/snippet}
{#snippet trailingSlot()}
<Button size="xs" variant="solid" color="primary" label="Go" />
{/snippet}
</Input>Props
| Prop | Type | Default |
|---|---|---|
value | InputValue | - |
type | string | 'text' |
variant | 'outline' | 'soft' | 'subtle' | 'ghost' | 'none' | 'outline' |
color | ColorType | 'primary' |
size | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' |
highlight | boolean | false |
loading | boolean | false |
loadingIcon | string | icons.loading |
icon | string | - |
leadingIcon | string | - |
trailingIcon | string | - |
trailing | boolean | false |
avatar | AvatarProps | - |
placeholder | string | - |
disabled | boolean | false |
id | string | - |
name | string | - |
ref | HTMLInputElement | null | - |
class | string | - |
ui | Record<Slot, Class> | - |