# Input

A single line of text, as plain text, a password or a file path.

```slint
import { Input } from "@glint/components/input.slint";
import { Tokens } from "@glint/theme/tokens.slint";

export component Demo inherits Window {
    width: 560px;
    height: 300px;
    background: Tokens.color-background;

    in-out property <string> user-name: "";

    VerticalLayout {
        alignment: center;
        spacing: 16px;
        padding: 24px;

        HorizontalLayout {
            alignment: center;

            VerticalLayout {
                width: 320px;

                Input {
                    placeholder: "Enter full name…";
                    text <=> root.user-name;
                }
            }
        }

        Text {
            text: root.user-name != "" ? "Value: " + root.user-name : "Input is empty";
            color: Tokens.color-muted-foreground;
            font-size: Tokens.typography-body-sm-size;
            horizontal-alignment: center;
        }
    }
}
```

## Usage

```slint
import { Input } from "@glint/components/input.slint";

export component AppWindow inherits Window {
    in-out property <string> email: "";

    VerticalLayout {
        alignment: center;

        Input {
            placeholder: "name@example.com";
            text <=> root.email;
            edited(new-text) => {
                // handle keystroke
            }
            accepted(committed-text) => {
                // handle enter submission
            }
        }
    }
}
```

`Input` provides a single-line text entry field styled with Glint design tokens and interactive focus ring outlines. Keyboard users can type, edit, and press `Enter` to submit.

## Examples

### Input variants

The `variant` property specifies what type of content the field manages:

- `InputVariant.text`: Standard single-line text entry.
- `InputVariant.password`: Obscured text entry rendered as bullet characters.
- `InputVariant.file`: File picker trigger button that fires `browse()` on click or `Enter`.

```slint
import { Input, InputVariant } from "@glint/components/input.slint";
import { Tokens } from "@glint/theme/tokens.slint";

export component Demo inherits Window {
    width: 560px;
    height: 340px;
    background: Tokens.color-background;

    in-out property <string> chosen-file: "";

    VerticalLayout {
        alignment: center;
        spacing: 16px;
        padding: 24px;

        HorizontalLayout {
            alignment: center;

            VerticalLayout {
                width: 320px;
                spacing: 12px;

                Input {
                    variant: InputVariant.text;
                    placeholder: "Standard text";
                    text: "developer@glint-ui.org";
                }

                Input {
                    variant: InputVariant.password;
                    placeholder: "Enter password";
                    text: "secret-passphrase";
                }

                Input {
                    variant: InputVariant.file;
                    text <=> root.chosen-file;
                    placeholder: "Select artifact…";
                    browse => {
                        root.chosen-file = "document-export.pdf";
                    }
                }
            }
        }
    }
}
```

### Read-only and disabled states

Set `read-only: true` to allow focusing, selecting, and copying text without permitting edits. Set `enabled: false` to dim the input and disable interaction entirely.

```slint
import { Input } from "@glint/components/input.slint";
import { Tokens } from "@glint/theme/tokens.slint";

export component Demo inherits Window {
    width: 560px;
    height: 300px;
    background: Tokens.color-background;

    VerticalLayout {
        alignment: center;
        padding: 24px;

        HorizontalLayout {
            alignment: center;

            VerticalLayout {
                width: 320px;
                spacing: 12px;

                Input {
                    read-only: true;
                    text: "READONLY-SYSTEM-TOKEN";
                }

                Input {
                    enabled: false;
                    text: "Disabled field content";
                }
            }
        }
    }
}
```

### Validation error state

Set `invalid: true` to display a destructive error border.

```slint
import { Input } from "@glint/components/input.slint";
import { Tokens } from "@glint/theme/tokens.slint";

export component Demo inherits Window {
    width: 560px;
    height: 300px;
    background: Tokens.color-background;

    VerticalLayout {
        alignment: center;
        padding: 24px;

        HorizontalLayout {
            alignment: center;

            VerticalLayout {
                width: 320px;

                Input {
                    invalid: true;
                    text: "invalid-email-address";
                }
            }
        }
    }
}
```

## API Reference

### Properties

| Property      | Type              | Default                                   | Description                                                                                                                       |
| ------------- | ----------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `text`        | `in-out string`   | no default                                | Two-way bound to the field contents. In the `file` variant this is the chosen file's name, written by the host after `browse()`.  |
| `variant`     | `in InputVariant` | `InputVariant.text`                       | What the field holds — see `InputVariant`.                                                                                        |
| `placeholder` | `in string`       | `root.picking ? @tr("Choose file…") : ""` | Hint shown when the field is empty. A file field defaults to saying what it is waiting for, since it has no typing to invite.     |
| `enabled`     | `in bool`         | `true`                                    | When false, the input dims and stops accepting keystrokes.                                                                        |
| `read-only`   | `in bool`         | `false`                                   | When true, the user can focus but not edit.                                                                                       |
| `auto-focus`  | `in bool`         | `false`                                   | When true, the input grabs focus on mount.                                                                                        |
| `invalid`     | `in bool`         | `false`                                   | When true, paints the border in destructive state. The message that explains the error belongs to the surrounding `Field`.        |
| `has-focus`   | `out bool`        | no default                                | Whether the entry currently holds keyboard focus — also whether the focus ring is drawn, which is what makes the ring assertable. |

### Callbacks

| Callback           | Description                                                                                                                               |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `edited(string)`   | Fired on every keystroke with the current text.                                                                                           |
| `accepted(string)` | Fired on Enter with the current text. A file field has no text to accept, so there Enter asks for the picker instead.                     |
| `browse()`         | Fired when the user asks the `file` variant for the picker. Open the platform's dialog and write the chosen file's name back into `text`. |

### Enums

| Enum           | Values                     |
| -------------- | -------------------------- |
| `InputVariant` | `text`, `password`, `file` |

## Accessibility

- **Text input role.** Publishes a single `accessible-role: text-input` node with `accessible-value: root.text`.
- **Read-only vs Disabled.** `accessible-read-only` and `accessible-enabled` are kept distinct so assistive technology does not announce read-only content as dead.
- **`invalid` announces the word “Invalid”.** Slint 1.17 publishes no `accessible-invalid`, so the state rides the description channel ADR-0013 opened: the control’s own description first, then `"Invalid"` after it. A red border is not the announcement — this is.
- **Focus ring.** Displays a focus ring when focused by keyboard or pointer navigation.
