Input
Input wraps the native <input>, so every DOM attribute (type, placeholder, value,
onChange, disabled, aria-*) passes straight through. It is controlled iff value is set.
Add a label (wired via htmlFor), a hint, or an error that swaps in error styling and
aria-invalid.
Examples
Label and hint
A label is not optional in practice: a placeholder disappears the moment someone types, taking
the only description of the field with it.
Sizes and inline icon
Heights match Button (sm 32px, md 40px, lg 48px), so fields and actions line up on the same row.
iconLeft sits inside the field and is decorative — it never replaces the label.
Error and disabled
error replaces hint, so a field shows one message at a time and the layout never jumps between
states.
Inside a form
Validate on submit, not on every keystroke — an error that appears while someone is still typing
their first character is noise. name and required are native attributes passed straight
through, so the field works with FormData and with any form library.
When to use
Use an Input for a single line of free-form text or a native typed value (email, password,
number, date — set type and the platform keyboard and validation follow).
Reach for something else when:
- The answer is more than a line — use a Textarea.
- The answer comes from a known list — use Select for a short list, Combobox when it is long enough to need filtering.
- It is a yes/no — use Checkbox or Switch.
- It is a file — use FileUpload.
Accessibility
- The
labelis wired to the control withhtmlFor/id, so clicking it focuses the field and screen readers announce the name. An Input without alabelneeds anaria-labelfrom you. errorsetsaria-invalidand is referenced by the field, so the message is announced rather than being colour-only feedback.hintanderrorshare one slot and one id: only one is rendered at a time, so there is never a stale description pointing at the field.- Focus is the
--shadow-focusring; the error state changes the border, never the focus ring.
Props
| Name | Type | Required | Description |
|---|---|---|---|
label | string | — | Label rendered above the field, wired to the input via `htmlFor`. |
hint | string | — | Helper text rendered below the field. Replaced by `error` when that is set. |
error | string | — | Error message — enables the error styling (`.lyra-input--error` + `.lyra-hint--error`), sets `aria-invalid`, and replaces `hint`. |
size | 'sm' | 'md' | 'lg' | — | Control height. Default `"md"` (sm 32px · md 40px · lg 48px). |
iconLeft | ReactNode | — | Icon rendered inside the field, on the left (e.g. `<Icon name="search" size={16} />`). |
Plain HTML
The field wrapper carries the layout; the icon variant needs the extra lyra-input-wrap:
<div class="lyra-field">
<label class="lyra-label" for="email">Work email</label>
<input class="lyra-input" id="email" type="email" placeholder="[email protected]" />
<span class="lyra-hint">We only use it for deploy notifications.</span>
</div>
<div class="lyra-field">
<label class="lyra-label" for="slug">Workspace slug</label>
<input class="lyra-input lyra-input--error" id="slug" aria-invalid="true" value="my workspace" />
<span class="lyra-hint lyra-hint--error">Use lowercase and dashes.</span>
</div>