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"
    />
  );
}

安装

批量导入

import { Input } from "@cloudflare/kumo";

细粒度导入

import { Input } from "@cloudflare/kumo/components/input";

用法

使用 label 属性即可启用内置的 Field 包装,获得标签、说明与错误提示支持。

import { Input } from "@cloudflare/kumo";

export default function Example() {
  return (
    <Input
      label="Email"
      placeholder="you@example.com"
      description="We'll never share your email"
    />
  );
}

裸 Input(自定义布局)

自定义表单布局时,可不使用 label 直接使用 Input。此时必须提供 aria-label 或 aria-labelledby 以保证无障碍。

import { Input } from "@cloudflare/kumo";

export default function Example() {
  return <Input placeholder="Search..." aria-label="Search products" />;
}

示例

带标签与说明

label 属性会启用内置的 Field 包装,并自动采用垂直布局 (标签位于输入框上方)。

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"
    />
  );
}

错误提示 (字符串)

将 error 作为字符串传入即可显示简单的错误消息。当 error 属性为真值时, 会自动应用错误样式。

Please enter a valid email address
import { Input } from "@cloudflare/kumo";

export function InputErrorStringDemo() {
  return (
    <Input
      label="Email"
      placeholder="you@example.com"
      value="invalid-email"
      error="Please enter a valid email address"
    />
  );
}

错误提示 (校验对象)

将 error 作为包含 message 和 match 的对象传入,可用于 HTML5 校验。 当字段的有效性与 match 匹配时显示错误。

import { Input } from "@cloudflare/kumo";

export function InputErrorObjectDemo() {
  return (
    <Input
      label="Password"
      type="password"
      value="short"
      error={{
        message: "Password must be at least 8 characters",
        match: "tooShort",
      }}
      minLength={8}
    />
  );
}

Input 尺寸

提供四种尺寸:xs、sm、base(默认)、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>
  );
}

禁用

import { Input } from "@cloudflare/kumo";

export function InputDisabledDemo() {
  return <Input label="Disabled field" placeholder="Cannot edit" disabled />;
}

可选字段

设置 required={false} 可在标签后显示「(选填)」文本。

import { Input } from "@cloudflare/kumo";

export function InputOptionalFieldDemo() {
  return (
    <Input
      label="Phone Number"
      required={false}
      placeholder="+1 (555) 000-0000"
    />
  );
}

带标签提示框

使用 labelTooltip 可添加一个信息图标,悬停时显示补充说明。

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 属性接受 ReactNode,可实现富文本格式的标签。

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"
    />
  );
}

通过 onChange 受控

标准的 React onChange 处理函数接收完整的事件对象,使用 e.target.value 获取值。

Uses e.target.value

import { useState } from "react";
import { Input } from "@cloudflare/kumo";

/** Controlled input using `onChange` (native React event). */
export function InputControlledOnChangeDemo() {
  const [value, setValue] = useState("");
  return (
    <Input
      label="With onChange"
      placeholder="Type something..."
      description={value ? `Value: ${value}` : "Uses e.target.value"}
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}

通过 onValueChange 受控

onValueChange 是 Base UI 提供的便捷处理函数,直接给出字符串值——无需再从事件中 解包。Select、Combobox 和 Radio.Group 采用的也是这一模式。

Receives the value directly

import { useState } from "react";
import { Input } from "@cloudflare/kumo";

/** Controlled input using `onValueChange` (Base UI convenience — gives you the string directly). */
export function InputControlledOnValueChangeDemo() {
  const [value, setValue] = useState("");
  return (
    <Input
      label="With onValueChange"
      placeholder="Type something..."
      description={value ? `Value: ${value}` : "Receives the value directly"}
      value={value}
      onValueChange={(v) => setValue(v)}
    />
  );
}

裸 Input(无标签)

不带 label 的 Input 会渲染为裸输入框。必须提供 aria-label 以保证无障碍。

import { Input } from "@cloudflare/kumo";

export function InputBareDemo() {
  return <Input placeholder="Search..." aria-label="Search products" />;
}

无标签时的错误提示

即使没有可见的 label,错误消息和说明仍会渲染——使用 aria-label 保证输入框的无障碍可用性。

Please enter a valid hostname
Path must start with /
import { Input } from "@cloudflare/kumo";

/** Input without a visible label, showing error and description via `aria-label`. */
export function InputErrorWithoutLabelDemo() {
  return (
    <div className="flex flex-col gap-4">
      <Input
        aria-label="Hostname"
        placeholder="example.com"
        value="not a host"
        error="Please enter a valid hostname"
      />
      <Input
        aria-label="Path"
        placeholder="/api/v1/users"
        value="missing-slash"
        error={{ message: "Path must start with /", match: true }}
      />
    </div>
  );
}

Input 类型

支持所有 HTML input 类型:text、email、password、number、tel、 url 等。

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>
  );
}

密码管理器浮层

对于密码管理器可能误判为登录字段的非凭据输入框,设置 passwordManagerIgnore。

import { Input } from "@cloudflare/kumo";

/** Side-by-side comparison: Keeper shows its icon on the default input but not the ignored one. */
export function InputPasswordManagerIgnoreDemo() {
  return (
    <div className="flex flex-col gap-4">
      <Input
        label="API Key (default)"
        type="password"
        placeholder="sk_live_..."
      />
      <Input
        label="API Key (passwordManagerIgnore)"
        type="password"
        placeholder="sk_live_..."
        passwordManagerIgnore
      />
    </div>
  );
}

API 参考

Input 接受所有标准 HTML input 属性,以及以下属性:

属性类型默认值说明
labelReactNode-Label content for the input (enables Field wrapper) - can be a string or any React node
labelTooltipReactNode-Tooltip content to display next to the label via an info icon
descriptionReactNode-Helper text displayed below the input
errorstring | object-Error message or validation error object
passwordManagerIgnoreboolean-Suppress browser extension password manager overlays on non-credential inputs.
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

校验错误类型

将 error 作为对象使用时,match 属性对应 HTML5 ValidityState 的取值:

Match说明
valueMissing必填字段为空
typeMismatch值与类型不匹配 (如无效的邮箱地址)
patternMismatch值与 pattern 属性不匹配
tooShort值短于 minLength
tooLong值长于 maxLength
rangeUnderflow值小于 min
rangeOverflow值大于 max
true始终显示错误 (用于服务端校验)

无障碍

标签要求

输入框需要通过以下方式之一获得可访问名称:

  • label 属性 (推荐)
  • 裸输入框使用 placeholder + aria-label
  • 使用 aria-labelledby 自定义标签关联

缺少可访问名称时,开发环境会在控制台输出警告。

错误提示关联

错误消息会通过 ARIA 属性自动与输入框关联,以便屏幕阅读器朗读。