Input
A versatile Input component that provides form-friendly input fields with integrated labels, error handling, and optional left/right sections. Built with accessibility and customization in mind.
Props
| Name | Type | Default | Description |
|---|---|---|---|
label | string | — | Label text displayed above the input. |
errors | `string[] | string | ReactNode` |
required | boolean | false | Shows a required indicator (asterisk) next to the label. |
leftSection | ReactNode | — | Content displayed on the left side inside the input. |
rightSection | ReactNode | — | Content displayed on the right side inside the input. |
labelProps | ComponentPropsWithoutRef<"label"> | — | Props passed to the label element. |
labelPosition | `"x" | "y"` | "y" |
...rest | ComponentPropsWithoutRef<"input"> | — | Any native <input> props are forwarded. |
Note The component automatically applies number pattern validation for type="number" inputs.
Usage
Basic Input
The most basic usage includes a label and placeholder.
<Input
label="Full Name"
placeholder="Enter your name"
required
/>
Preview
Input with Errors
Pass an array of strings to the errors prop to display validation messages. The component will automatically apply error styling.
<Input
label="Email"
placeholder="you@example.com"
defaultValue="not-an-email"
errors={["Please enter a valid email"]}
/>
Preview
Input with Sections (Prefix/Suffix)
Use leftSection and rightSection to add prefixes, suffixes, icons, or buttons inside the input.
<Input
label="Amount"
placeholder="0.00"
type="number"
leftSection={<span style={{ padding: "0 8px", opacity: 0.7 }}>$</span>}
rightSection={<span style={{ padding: "0 8px", opacity: 0.7 }}>USD</span>}
/>
Preview
Password Input with Show/Hide
You can use the rightSection to create a toggle for password visibility.
function PasswordInput() {
const [visible, setVisible] = React.useState(false);
return (
<Input
label="Password"
placeholder="Enter password"
type={visible ? "text" : "password"}
rightSection={
<button
type="button"
onClick={() => setVisible((v) => !v)}
style={{ border: "none", background: "transparent", cursor: "pointer" }}
aria-label={visible ? "Hide password" : "Show password"}
>
{visible ? "🙈" : "👁️"}
</button>
}
required
/>
);
}
Preview
Horizontal Label Layout
Set labelPosition="x" to align the label and input horizontally. You may need to provide a minWidth to the label via labelProps for alignment.
<Input
label="Username"
placeholder="john_doe"
labelPosition="x"
labelProps={{ style: { minWidth: "100px" } }}
/>
Preview
Disabled Input
Pass the native disabled prop to disable interaction and apply disabled styles.
<Input
label="Disabled Field"
placeholder="Cannot edit"
disabled
defaultValue="Some read-only value"
/>
Preview
Accessibility
- Semantics: Renders a proper
<label>element linked to the input viahtmlFor. - Error states: Errors are announced to screen readers via the
data-errorattribute. - Required fields: Visual indicator (asterisk) and semantic
requiredattribute. - Keyboard navigation: Full keyboard support inherited from native input.
Tip Always provide descriptive labels and error messages for screen reader users.
Styles & customization
Runtime classes
kui-input-container: The main wrapper for the label, input, and error message.kui-input-inner: The direct wrapper around the input field and its sections.kui-input: The<input>element itself.kui-input-label: The<label>element.kui-input-error-message: The<span>that displays the error message.
Tokens used by the default styles
- Colors:
--kui-neutral-*,--kui-primary-*,--kui-danger-* - Spacing:
--kui-spacing-2xs,--kui-spacing-xs,--kui-spacing-sm - Typography:
--kui-text-base,--kui-text-sm - Rounding:
--kui-rounded
Types (reference)
import { ComponentPropsWithoutRef, ReactNode } from "react";
type LabelPositionBase = "x" | "y";
export type InputProps = ComponentPropsWithoutRef<"input"> & {
label?: string;
labelProps?: ComponentPropsWithoutRef<"label">;
errors?: string[] | string | ReactNode;
required?: boolean;
onMaxExited?: VoidFunction;
leftSection?: ReactNode;
rightSection?: ReactNode;
labelPosition?: LabelPositionBase;
};