Input
A single-line text field.
Playground
<Input
error=""
helper="We will never share your email"
label="Email"
placeholder="name@example.com"
/>01 Examples
Search input
clearable with a left search icon. Press Escape or click the clear button to reset.<Input
clearable
bind:value={searchValue}
placeholder="Search anything..."
aria-label="Search"
>
{#snippet leftIcon()}
<SearchIcon />
{/snippet}
</Input>Password with visibility toggle
rightIconAriaLabel or leftIconAriaLabel for a name. A right icon and clearable share the same corner: while the field holds a value, the clear control takes it.<Input
type={passwordVisible ? 'text' : 'password'}
label="Password"
placeholder="Enter your password"
bind:value={passwordValue}
onRightIconClick={() => (passwordVisible = !passwordVisible)}
rightIconAriaLabel={passwordVisible ? 'Hide password' : 'Show password'}
>
{#snippet leftIcon()}
<LockIcon />
{/snippet}
{#snippet rightIcon()}
{#if passwordVisible}
<EyeOffIcon />
{:else}
<EyeIcon />
{/if}
{/snippet}
</Input>Validated in a form
type and required sit on a real input, so the browser checks the address shape and the empty case before the handler runs, while name is what puts the value into the FormData. error covers what only your code knows, an answer from the server for instance, and it overrides helper and any intent for as long as it is set.<form class="flex flex-col gap-4" onsubmit={handleSignup}>
<Input
type="email"
name="email"
label="Email"
placeholder="name@example.com"
value="ada@example.com"
error={emailError}
helper="We send one confirmation mail and nothing else"
required
>
{#snippet leftIcon()}
<MailIcon />
{/snippet}
</Input>
<Button type="submit" size="sm" class="self-start">Sign up</Button>
{#if signedUp}
<p class="text-success text-xs">Address accepted.</p>
{/if}
</form>02 Customization
Prominent search bar
container slot and the text field to base, so a treatment on the outside goes on the first while the second gives up its own border and ring.<Input
tier="commit"
size="lg"
clearable
bind:value={brandedSearch}
placeholder="Search components, patterns, tokens..."
aria-label="Search"
slotClasses={{
container:
'shadow-[var(--blocks-shadow-lg)] ring-2 ring-primary/25 focus-within:ring-primary/50 transition-shadow overflow-hidden',
base: 'border-transparent bg-transparent focus-visible:ring-0'
}}
>
{#snippet leftIcon()}
<SearchIcon />
{/snippet}
</Input>A field that reads as the text around it
bare variant drops the frame, the fill, the padding and the fixed height — size keeps only the type step. It needs context that says it is a field: a placeholder, a rule under the line, a label before it. The one thing it does not drop is the focus indicator: an outline whose colour is --blocks-focus-ring-color, so a product where the accent means something else sets the focus colour once instead of per call site.<div
class="text-text-primary border-border-subtle flex items-baseline gap-1 border-b pb-1 text-base"
>
<span>Remind me to</span>
<Input
variant="bare"
bind:value={bareValue}
placeholder="write the release note"
aria-label="Reminder"
class="flex-1"
/>
</div>A form where everything is required
requiredMark slot, so hiding it once covers the whole app — the GOV.UK convention of marking nothing when every field is required. Use overrides instead of slotClasses when only the required state should change.<BlocksProvider
defaults={{
Input: { slotClasses: { requiredMark: 'hidden' } },
Select: { overrides: [{ required: true, class: { requiredMark: 'hidden' } }] }
}}
>
<SignupForm />
</BlocksProvider>A treatment every field should share belongs on a BlocksProvider instead, as a defaults entry for Input and the same one for Select and Textarea. See Customization for that and for class, slotClasses, unstyled and preset.
03 Accessibility
Labels and messages
The label links to the field via for/id. helper and error text is announced through aria-describedby, and an error also sets aria-invalid on the input.
Keyboard
Tab focuses the field. On a clearable field that holds a value, Escape clears it and puts focus back in the input, which is also the one case where
a field inside a dialog keeps that Escape to itself. An icon with a click handler is a real <button> with its own Tab stop, before the field on the left and after it on the right, and the clear
control is another one.
Colour is not the only signal
An intent tints the field's frame and nothing else,
so a state carried by it wants helper text saying the
same thing in words. An error arrives with its message
already attached.
04 API Reference
35 propsProp | Type | Default | Description | |
|---|---|---|---|---|
autoComplete | string | — | HTML autocomplete hint for browser autofill. | |
children | Snippet | — | Snippet content rendered below the input for advanced layouts. | |
class | string | — | Extra classes merged onto the root wrapper element. | |
clearable | boolean | false | Show a clear button when the input has a value.
Press Escape or click the button to clear. Fires onClear after clearing. | |
disabled | boolean | false | disabled property | |
error | string | — | Error message below the input. When set, overrides helper and
forces danger border styling regardless of intent. | |
hasLeftIcon variant | true | false | Controls the hasLeftIcon behavior and appearance of the Input component. Available options: true. | |
hasRightIcon variant | true | false | Controls the hasRightIcon behavior and appearance of the Input component. Available options: true. | |
helper | string | — | Helper text below the input — hidden when error is present. | |
iconPosition variant | leftright | left | Controls the iconPosition behavior and appearance of the Input component. Available options: left, right. | |
intent variant | dangerdefaultsuccesswarning | default | Controls the color theme and semantic meaning of the Input. Affects the overall appearance and user perception. Available options: danger, default, success, warning. | |
label | string | — | Label text displayed above the input, auto-linked via for/id. | |
leftIcon | Snippet | — | Icon snippet rendered on the left side of the input field. | |
leftIconAriaLabel | string | — | Accessible label for the clickable left icon button. Required when
onLeftIconClick is set so screen-reader users hear a name for the
button (icons inside are aria-hidden). | |
mint | MintProp | 'none' | Micro-interaction preset applied to the input element. Only applies while not disabled. | |
onClear | () => void | — | Fired after the value is cleared via the clear button or Escape key. | |
onLeftIconClick | () => void | — | When provided, the left icon becomes a clickable button. | |
onRightIconClick | () => void | — | When provided, the right icon becomes a clickable button. | |
persistDebounceMs | number | 300 | Debounce interval (ms) for storage writes. | |
persistKey | string | — | Key for persisting the input value to storage. | |
persistNamespace | string | — | Namespace (e.g. user id) to scope the persist key. | |
persistStorage | localStoragesessionStorage | 'localStorage' | Storage backend for persistence. | |
persistVersion | number | 1 | Version stamp included in the storage key. | |
preset | string | — | Apply a named preset registered via <BlocksProvider presets={{ Input: {...} }}>.
Prefer this over class overrides when the requested look falls outside the
semantic intent palette — presets keep hover/active/dark-mode logic coherent
and make the custom look reusable across the project. | |
readonly | boolean | false | readonly property | |
required | boolean | false | Adds a required asterisk to the label and sets the native required attribute. | |
rightIcon | Snippet | — | Icon snippet rendered on the right side of the input field. | |
rightIconAriaLabel | string | — | Accessible label for the clickable right icon button. Required when
onRightIconClick is set so screen-reader users hear a name for the
button (icons inside are aria-hidden). | |
size variant | lgmdsmxl +1 more | md | Controls the dimensions, padding, and text size of the Input. Affects the component's physical footprint. Available options: lg, md, sm, and 2 more. | |
slotClasses | Partial<Record<InputSlots, string>> | — | Per-slot class overrides merged with tv() styles. Slots: wrapper (root —
what class also targets) | container | base (the <input> element) |
label | requiredMark | message | iconContainer | iconButton | iconDecoration. | |
tier variant | commitmodify | modify | Selects the semantic radius tier of the Input — the shape family it belongs to (--radius-commit/-modify/-contain/-bridge). Shape is retuned per family in your theme, so this picks the family rather than a pixel value. Available options: commit, modify. | |
unstyled | boolean | — | Remove all default tv() classes — only user-provided classes apply. | |
variant variant | barefilledghostoutlined +1 more | outlined | Controls the visual style and presentation of the Input. Determines the component's visual treatment. Available options: bare, filled, ghost, and 2 more. | |
...HTMLInputAttributes inherited | HTMLAttributes | — | HTML attributes (excluding: 'size' | 'class' | 'disabled' | 'readonly' | 'children') | |
...InputVariants variant | VariantProps | — | Styling variants from InputVariants |
05 Types
Local type definitions used by this component.
Name | Kind | Category | Used by | Description | |
|---|---|---|---|---|---|
InputProps | interface | props | 0 | — | |
InputVariants | type | variant | 0 | — | |
InputSlots | type | variant | 0 | Slot names derived from the tv() config above — single source of truth for slotClasses. | |
MintProp | type | helper | 1 | — | |
MintName | type | helper | 0 | A mint name: a built-in (autocompleted), 'none' to disable, or any
consumer-registered name. (string & {}) keeps the registry open — a
custom name still type-checks, it just isn't suggested. A typo therefore
also still compiles (it resolves like an unregistered custom name and
warns at runtime); the union buys completion and docs, not validation. | |
MintConfig | interface | helper | 0 | — | |
BuiltinMintName | type | helper | 0 | Built-in mint names as a literal union, so the mint prop autocompletes
across every component — the single list the hand-curated playground knobs
and docs used to drift away from. |
06 Installation
Import
import { Input } from '@urbicon-ui/blocks';