We'll never share your email
import { Input } from "@cloudflare/kumo";
export function InputBasicDemo() {
return (
<Input
label="Email"
placeholder="you@example.com"
description="We'll never share your email"
/>
);
} Installation
Barrel
import { Input } from "@cloudflare/kumo"; Granular
import { Input } from "@cloudflare/kumo/components/input"; Usage
With Built-in Field (Recommended)
Use the label prop to enable the built-in Field wrapper with label, description, and error support.
import { Input } from "@cloudflare/kumo";
export default function Example() {
return (
<Input
label="Email"
placeholder="you@example.com"
description="We'll never share your email"
/>
);
}Bare Input (Custom Layouts)
For custom form layouts, use Input without label. Must provide aria-label
or aria-labelledby for accessibility.
import { Input } from "@cloudflare/kumo";
export default function Example() {
return <Input placeholder="Search..." aria-label="Search products" />;
} Examples
With Label and Description
The label prop enables the built-in Field wrapper with automatic vertical
layout (label above input).
3-20 characters, alphanumeric only
import { Input } from "@cloudflare/kumo";
export function InputWithLabelDemo() {
return (
<Input
label="Username"
placeholder="Choose a username"
description="3-20 characters, alphanumeric only"
/>
);
} With Error (String)
Pass error as a string for simple error messages. Error replaces description
when present.
import { Input } from "@cloudflare/kumo";
export function InputErrorStringDemo() {
return (
<Input
label="Email"
placeholder="you@example.com"
value="invalid-email"
variant="error"
error="Please enter a valid email address"
/>
);
} With Error (Validation Object)
Pass error as an object with message and match for HTML5 validation.
Error shows when field validity matches.
import { Input } from "@cloudflare/kumo";
export function InputErrorObjectDemo() {
return (
<Input
label="Password"
type="password"
value="short"
variant="error"
error={{
message: "Password must be at least 8 characters",
match: "tooShort",
}}
minLength={8}
/>
);
} Input Sizes
Four sizes available: xs, sm, base (default), lg.
import { Input } from "@cloudflare/kumo";
export function InputSizesDemo() {
return (
<div className="flex flex-col gap-4">
<Input size="xs" label="Extra Small" placeholder="Extra small input" />
<Input size="sm" label="Small" placeholder="Small input" />
<Input label="Base" placeholder="Base input (default)" />
<Input size="lg" label="Large" placeholder="Large input" />
</div>
);
} Disabled
import { Input } from "@cloudflare/kumo";
export function InputDisabledDemo() {
return <Input label="Disabled field" placeholder="Cannot edit" disabled />;
} Optional Field
Set required={false} to show “(optional)” text after the label.
import { Input } from "@cloudflare/kumo";
export function InputOptionalFieldDemo() {
return (
<Input
label="Phone Number"
required={false}
placeholder="+1 (555) 000-0000"
/>
);
} With Label Tooltip
Use labelTooltip to add an info icon with additional context on hover.
import { Input } from "@cloudflare/kumo";
export function InputLabelTooltipDemo() {
return (
<Input
label="API Key"
labelTooltip="Find this in your dashboard under Settings > API Keys"
placeholder="sk_live_..."
/>
);
} ReactNode Label
The label prop accepts ReactNode for rich formatting.
import { Input } from "@cloudflare/kumo";
export function InputReactNodeLabelDemo() {
return (
<Input
label={
<span>
Email for <strong>billing</strong>
</span>
}
required
placeholder="billing@company.com"
type="email"
/>
);
} Bare Input (No Label)
Input without label renders as a bare input. Must provide aria-label for
accessibility.
import { Input } from "@cloudflare/kumo";
export function InputBareDemo() {
return <Input placeholder="Search..." aria-label="Search products" />;
} Input Types
Supports all HTML input types: text, email, password, number, tel, url, etc.
import { Input } from "@cloudflare/kumo";
export function InputTypesDemo() {
return (
<div className="flex flex-col gap-4">
<Input type="email" label="Email" placeholder="you@example.com" />
<Input type="password" label="Password" placeholder="••••••••" />
<Input type="number" label="Age" placeholder="18" />
<Input type="tel" label="Phone" placeholder="+1 (555) 000-0000" />
</div>
);
} API Reference
Input accepts all standard HTML input attributes plus the following:
| Prop | Type | Default | Description |
|---|---|---|---|
| label | ReactNode | - | Label content for the input (enables Field wrapper) - can be a string or any React node |
| labelTooltip | ReactNode | - | Tooltip content to display next to the label via an info icon |
| description | ReactNode | - | Helper text displayed below the input |
| error | string | object | - | Error message or validation error object |
| size | "xs" | "sm" | "base" | "lg" | "base" | Input size. - `"xs"` — Extra small for compact UIs - `"sm"` — Small for secondary fields - `"base"` — Default size - `"lg"` — Large for prominent fields |
| variant | "default" | "error" | "default" | Visual variant. - `"default"` — Standard input - `"error"` — Error state for validation failures |
Validation Error Types
When using error as an object, the match property corresponds to HTML5 ValidityState values:
| Match | Description |
|---|---|
| valueMissing | Required field is empty |
| typeMismatch | Value doesn’t match type (e.g., invalid email) |
| patternMismatch | Value doesn’t match pattern attribute |
| tooShort | Value shorter than minLength |
| tooLong | Value longer than maxLength |
| rangeUnderflow | Value less than min |
| rangeOverflow | Value greater than max |
| true | Always show error (for server-side validation) |
Accessibility
Label Requirement
Inputs require an accessible name via one of:
labelprop (recommended)placeholder+aria-labelfor bare inputsaria-labelledbyfor custom label association
Missing accessible names trigger console warnings in development.
Error Association
Error messages are automatically associated with the input via ARIA attributes for screen reader announcement.