# Input

Enter text, add a clear button, and connect the value to your form or state.

An input is a native text field for short values like a name, an email address or a search. It works inside a field and a form, and adds a clear button, text around the input, and change reasons.

```svelte title="basic.svelte"
<script lang="ts">
  import { XIcon } from "@lucide/svelte"
  import { Field, FieldDescription, FieldLabel } from "@ui-sdk/svelte/field"
  import { Input, InputClear, InputGroup } from "@ui-sdk/svelte/input"
  import { useLog } from "./log"

  const log = useLog()
</script>

<Field name="website">
  <FieldLabel>Website</FieldLabel>
  <InputGroup>
    <span>https://</span>
    <Input
      placeholder="example.com"
      defaultValue="hollisgrant.com"
      onValueChange={(value, details) =>
        log(`${value ? `“${value}”` : "Empty"} (${details.reason})`)}
    />
    <InputClear aria-label="Clear website">
      <XIcon aria-hidden="true" />
    </InputClear>
  </InputGroup>
  <FieldDescription>Shown on your public profile.</FieldDescription>
</Field>
```

Edit the website, then press Clear website. The text clears, focus returns to the input and the console logs the reason. Pressing https:// focuses the input too.

## Installation

```bash
npm install @ui-sdk/svelte @ui-sdk/core
```

## Composition

Use the following composition to build an `Input` or an `InputGroup`:

```text
Input

InputGroup
├── Input
└── InputClear
```

`Input` renders a native `<input>`. Pass its type, placeholder, autocomplete and other native attributes directly. `InputGroup` holds text or buttons around it, and `InputClear` empties it.

## Usage

Import the parts and put them together:

```svelte
<script lang="ts">
  import { Input, InputClear, InputGroup } from "@ui-sdk/svelte/input"
</script>

<InputGroup>
  <Input type="search" aria-label="Search" />
  <InputClear aria-label="Clear search" />
</InputGroup>
```

## Fields

Wrap the input in a [Field](/docs/svelte/components/field) to give it a visible label, a description and errors. The field also supplies its `name` when the input has none.

```svelte
<Field name="username">
  <FieldLabel>Username</FieldLabel>
  <Input autocomplete="username" />
  <FieldDescription>Choose a unique username for your account.</FieldDescription
  >
</Field>
```

## Disabled and Read Only

Set `disabled` on the input or its field to prevent editing and leave it out of the tab order and the submitted values. A `readOnly` input can still be focused, selected and submitted.

```svelte
<Field disabled>
  <FieldLabel>Email</FieldLabel>
  <Input type="email" defaultValue="hollis@example.com" />
</Field>

<Field>
  <FieldLabel>Profile URL</FieldLabel>
  <Input readOnly value="example.com/hollis" />
</Field>
```

## Validation

Use native constraints such as `required`, `type="email"` and `pattern`. The field shows its error after a submit attempt and updates it as the value changes. Set `invalid` on the field for an error your app decides; the input gets `aria-invalid`. [Field](/docs/svelte/components/field#validation) covers the error parts and their matches.

```svelte
<Field name="email" invalid={emailTaken ? true : undefined}>
  <FieldLabel>Email</FieldLabel>
  <Input type="email" required />
  <FieldError match="valueMissing">Enter your email address.</FieldError>
  <FieldError match>That email is already in use.</FieldError>
</Field>
```

## Input Group

Place text or buttons around an input with `InputGroup`. Pressing the group's text focuses the input. The text is display content, not part of the submitted value.

```svelte
<InputGroup>
  <span>https://</span>
  <Input aria-label="Website" placeholder="example" />
  <span>.com</span>
</InputGroup>
```

## Clear Button

`InputClear` shows while the input has text it can clear. Pressing it empties the value, reports `clear-press` and returns focus to the input. Controlled state and native input listeners receive the change too.

```svelte
<InputGroup>
  <Input type="search" aria-label="Search people" />
  <InputClear aria-label="Clear search">
    <XIcon aria-hidden="true" />
  </InputClear>
</InputGroup>
```

## Controlled

Bind `value` with `bind:value` to control the input. `onValueChange` also receives the change details, and native `oninput` still works.

```svelte
<script lang="ts">
  let name = $state("Hollis Grant")
</script>

<Input bind:value={name} />
```

See [State and Events](/docs/svelte/state-and-events) for the shared controlled-state conventions. Input's [reasons](#reasons) tell typing, clearing, resetting and controller changes apart.

## Filtering What's Typed

Call `details.cancel()` in `onValueChange` to reject a change. The previous text and caret position are restored.

```svelte
<Input
  inputmode="numeric"
  maxlength={6}
  onValueChange={(value, details) => {
    if (!/^\d*$/.test(value)) details.cancel()
  }}
/>
```

## Controller

Use `createInputController()` for actions outside the input. Its methods update the input through the same change callbacks as typing.

```svelte
<script lang="ts">
  const message = createInputController()
</script>

<Input controller={message} aria-label="Message" />
<button onclick={() => message.setValue("On my way!")}>Quick Reply</button>
<button onclick={() => message.clear()}>Clear</button>
<button onclick={() => message.focus()}>Focus</button>
```

[Controllers](/docs/svelte/controllers) covers creating and sharing a controller.

## Passwords and Files

Use [Password Input](/docs/svelte/components/password-input) to show and hide a password. A native file input works with `type="file"`; use [File Input](/docs/svelte/components/file-input) for dropping, previews and validation.

## Styling

Each part has a `data-slot`, such as `input-group`, and shows its state through the attributes listed under [Data Attributes](#data-attributes). Use `data-filled`, `data-disabled`, `data-readonly` and `data-required` on the input, and the field's validation and focus attributes inside a field. For a group's focus ring, style `:has(input:focus-visible)`, so a focused button inside it keeps its own ring.

## Data Attributes

### Input
`[data-slot="input"]`

- `data-filled`: Present while the field holds any text.
- `data-disabled`: Present when the field is disabled, by its own prop or its Field.
- `data-readonly`: Present when the field is read-only.
- `data-required`: Present when the field is required.

### InputGroup
`[data-slot="input-group"]`

- `data-filled`: Present while the field in the group holds any text.
- `data-disabled`: Present while the field in the group is disabled, by itself or a `<fieldset>`.
- `data-readonly`: Present while the field in the group is read-only.

### InputClear
`[data-slot="input-clear"]`

- `data-filled`: Present while the field in the group holds any text.
- `data-disabled`: Present while the field in the group is disabled, by itself or a `<fieldset>`.
- `data-readonly`: Present while the field in the group is read-only.

## API Reference

Props and callbacks are the same as below, as Svelte props, plus every native input attribute. `value` can be bound with `bind:value`.

### Input

- `value?` (`string`): The value, for a controlled field.
- `defaultValue?` (`string`): The value it starts with. A form reset returns here.
- `onValueChange?` (`((value: string, details: ChangeDetails<InputValueChangeReason>) => void)`): Called when the user changes the value: typing (`"input-change"`), a Clear part (`"clear-press"`), a form reset (`"reset"`) or a controller (`"imperative"`). `details.cancel()` keeps the value as it was.
- `controller?` (`object`): Reads and writes the field from anywhere. Create one with `createInputController()`.
- `debug?` (`boolean`): Logs every state change with its reason to the console, in development builds.

- `disabled?` (`boolean`): Disables the field.
- `readOnly?` (`boolean`): Makes the field read-only.
- `required?` (`boolean`): Makes the field required.

### InputGroup

- `debug?` (`boolean`): Logs every state change with its reason to the console, in development builds.

### InputClear

A `<button>` that empties the input in its group and focuses it. It renders only while there's text to clear.

### State

- `filled` (`boolean`): Whether the field holds any text.
- `disabled` (`boolean`): Whether the field is disabled.
- `readOnly` (`boolean`): Whether the field is read-only.
- `required` (`boolean`): Whether the field is required.

`InputGroup` and `InputClear` receive the state of the input inside the group.

- `filled` (`boolean`): Whether the field in the group holds any text.
- `disabled` (`boolean`): Whether the field in the group is disabled, by itself or by a `<fieldset>`.
- `readOnly` (`boolean`): Whether the field in the group is read-only.

### Reasons

- `input-change` (`Event`): Typing, pasting or dropping changed a text field's value; in a combobox it can also open or close it, or Enter keeps the typed text as the value.
- `clear-press` (`MouseEvent | KeyboardEvent`): A Clear part was pressed, like on an input, a select or a combobox.
- `reset` (`none`): A form reset.
- `imperative` (`none`): A controller or `api` call, or a property set on a web component.

### Controller

Create one with `createInputController()` and pass it as `controller`.

- `getValue()` (`() => string`): The current value.
- `setValue(value, options?)` (`(value: string, options?: ChangeOptions<InputValueChangeReason> | undefined) => boolean`): Sets the value as if the user typed it, so `input` fires. Returns false when the change was canceled or nothing changed.
- `clear(options?)` (`(options?: ChangeOptions<InputValueChangeReason> | undefined) => boolean`): Empties the field, as if the user deleted the text, so `input` fires. Returns false when the change was canceled or nothing changed.
- `focus()` (`() => void`): Moves focus to the field.

## Accessibility

Give the input a visible field label or an `aria-label`, and give the clear button an accessible name. The native input keeps standard text editing, selection, autocomplete and form behavior.

- The label names the input and the description describes it.
- Clicking the label focuses the input.
- An invalid input is marked once the form tries to submit.
- Data-filled follows the text.
- An input group's clear button shows only while there's text.
- <ui-input>'s value property writes the field quietly, and its api reports. Web components only.

**Enhancements**

- Changes report their reason: typing, then a reset.
- A canceled change keeps the text as it was.
- A canceled change keeps a controlled input's text as it was.
- A canceled change waits for an IME to finish before the text goes back.
- A controlled input keeps every keystroke.
- A required input marks its label required.

**Input group**

- The clear button empties the field, reports why, and returns focus.
- Pressing the group's text focuses its field.
- The clear button hides while its field is disabled.

Runs in React, Vue and web components.
