Skip to content
Lenso UI

TextField 文本输入框

便于组合的文本字段,包含标签、说明与内联校验。

用法

import { TextField } from '@lenso/ui';

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";
// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Input, Label, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ field: { width: "100%", maxWidth: 256 } });
export function Basic() {  return (    <TextField name="email" xstyle={styles.field}>      <Label>Email</Label>      <Input type="email" placeholder="Enter your email" />    </TextField>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

组件结构

import {TextField, Label, Input, Description, FieldError} from '@lenso/ui';
export default () => (  <TextField>    <Label />    <Input />    <Description />    <FieldError />  </TextField>)

TextField 将标签、输入、说明与错误信息整合为单个无障碍组件。若只需独立输入,请使用 Input 或 TextArea。

示例

表面样式

在 Surface 内使用时,请在 Input 或 TextArea 组件上使用 variant="secondary",以应用适合表面背景的低强调变体。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Input, Label, Surface, TextArea, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: {    display: "flex",    width: "100%",    minWidth: 340,    flexDirection: "column",    gap: 16,    borderRadius: 24,    padding: 24,  },});export function OnSurface() {  return (    <Surface xstyle={styles.root}>      <TextField name="name">        <Label>Your name</Label>        <Input fullWidth variant="secondary" placeholder="John" />        <Description>We'll never share this with anyone else</Description>      </TextField>      <TextField name="email">        <Label>Email</Label>        <Input type="email" fullWidth variant="secondary" placeholder="[email protected]" />      </TextField>      <TextField name="bio">        <Label>Bio</Label>        <TextArea fullWidth variant="secondary" placeholder="Tell us about yourself..." rows={4} />        <Description>Minimum 4 rows</Description>      </TextField>    </Surface>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

带描述

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Input, Label, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ field: { width: "100%", maxWidth: 256 } });export function WithDescription() {  return (    <TextField xstyle={styles.field} name="username">      <Label>Username</Label>      <Input placeholder="Enter username" />      <Description>Choose a unique username for your account</Description>    </TextField>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

必填字段

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Input, Label, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ field: { width: "100%", maxWidth: 256 } });export function Required() {  return (    <TextField xstyle={styles.field} name="fullName">      <Label>Full Name</Label>      <Input required placeholder="John Doe" />      <Description>This field is required</Description>    </TextField>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

禁用状态

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Input, Label, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ field: { width: "100%", maxWidth: 256 } });export function Disabled() {  return (    <TextField disabled xstyle={styles.field} name="accountId">      <Label>Account ID</Label>      <Input value="USR-12345" placeholder="Auto-generated" />      <Description>This field cannot be edited</Description>    </TextField>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

宽度充满

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { FieldError, Input, Label, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", width: 400, flexDirection: "column", gap: 16 },});export function FullWidth() {  return (    <div {...stylex.props(styles.root)}>      <TextField fullWidth name="name">        <Label>Your name</Label>        <Input placeholder="John" />      </TextField>      <TextField fullWidth invalid name="password">        <Label>Password</Label>        <Input required type="password" />        <FieldError match>Password must be longer than 8 characters</FieldError>      </TextField>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

表单校验

将 isInvalid 与 FieldError 配合使用,以展示校验消息。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, FieldError, Input, Label, TextArea, TextField } from "@lenso/ui";import * as React from "react";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", width: "100%", maxWidth: 256, flexDirection: "column", gap: 16 },});export function Validation() {  const [username, setUsername] = React.useState("");  const [bio, setBio] = React.useState("");  const isUsernameInvalid = username.length > 0 && username.length < 3;  const isBioInvalid = bio.length > 0 && bio.length < 20;  return (    <div {...stylex.props(styles.root)}>      <TextField invalid={isUsernameInvalid} name="username">        <Label>Username</Label>        <Input required value={username} onValueChange={setUsername} placeholder="jane_doe" />        {isUsernameInvalid ? (          <FieldError match>Username must be at least 3 characters.</FieldError>        ) : (          <Description style={{ display: "block" }}>            Choose a unique username for your profile.          </Description>        )}      </TextField>      <TextField invalid={isBioInvalid} name="bio">        <Label>Bio</Label>        <TextArea          required          value={bio}          onValueChange={setBio}          placeholder="Tell us about yourself..."        />        {isBioInvalid ? (          <FieldError match>Bio must contain at least 20 characters.</FieldError>        ) : (          <Description style={{ display: "block" }}>            Minimum 20 characters ({bio.length}/20).          </Description>        )}      </TextField>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

受控组件

控制 value 以同步计数器、预览或格式化逻辑。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Input, Label, TextArea, TextField } from "@lenso/ui";import * as React from "react";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", width: "100%", maxWidth: 256, flexDirection: "column", gap: 16 },});export function Controlled() {  const [name, setName] = React.useState("");  const [bio, setBio] = React.useState("");  return (    <div {...stylex.props(styles.root)}>      <TextField name="name">        <Label>Display name</Label>        <Input placeholder="Jane" value={name} onValueChange={setName} />        <Description>Characters: {name.length}</Description>      </TextField>      <TextField name="bio">        <Label>Bio</Label>        <TextArea placeholder="Tell us about yourself..." value={bio} onValueChange={setBio} />        <Description>Characters: {bio.length} / 200</Description>      </TextField>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

错误信息

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { FieldError, Input, Label, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ field: { width: "100%", maxWidth: 256 } });export function WithError() {  return (    <TextField invalid xstyle={styles.field} name="email">      <Label>Email</Label>      <Input type="email" placeholder="[email protected]" />      <FieldError match>Please enter a valid email address</FieldError>    </TextField>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

文本域

多行内容请使用 TextArea,而非 Input。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, TextArea, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ field: { width: "100%", maxWidth: 256 } });export function TextAreaExample() {  return (    <TextField xstyle={styles.field} name="message">      <Label>Message</Label>      <TextArea placeholder="Write your message here..." rows={4} />      <Description>Maximum 500 characters</Description>    </TextField>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Input 类型

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Input, Label, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", width: "100%", maxWidth: 256, flexDirection: "column", gap: 16 },});export function InputTypes() {  return (    <div {...stylex.props(styles.root)}>      <TextField name="password">        <Label>Password</Label>        <Input type="password" placeholder="••••••••" />      </TextField>      <TextField name="age">        <Label>Age</Label>        <Input type="number" max="150" min="0" placeholder="21" />      </TextField>      <TextField name="email">        <Label>Email</Label>        <Input type="email" placeholder="[email protected]" />      </TextField>      <TextField name="website">        <Label>Website</Label>        <Input type="url" placeholder="https://example.com" />      </TextField>      <TextField name="phone">        <Label>Phone</Label>        <Input type="tel" placeholder="+1 (555) 000-0000" />      </TextField>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

渲染函数

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Input, Label, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ field: { width: "100%", maxWidth: 256 } });export function RenderFunction() {  return (    <TextField      xstyle={styles.field}      name="email"      render={(props) => <div {...props} data-custom="foo" />}    >      <Label>Email</Label>      <Input type="email" placeholder="Enter your email" />    </TextField>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

自定义样式

Tailwind CSS

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Input, Label, TextField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { width: "100%", maxWidth: 256, gap: 6 },  label: {    fontWeight: 500,    color: { default: "oklch(26.9% 0 0)", ':is(.dark *, [data-theme="dark"] *)': "oklch(97% 0 0)" },  },  input: {    fontSize: 14,    borderRadius: 12,    borderWidth: 1,    borderStyle: "solid",    borderColor: "color-mix(in oklab, var(--border) 80%, transparent)",    backgroundColor: "var(--surface)",    color: { default: "oklch(26.9% 0 0)", ':is(.dark *, [data-theme="dark"] *)': "oklch(97% 0 0)" },    boxShadow: {      default: "0 1px 2px 0 rgb(0 0 0 / .05), 0 0 0 1px rgb(0 0 0 / .05)",      ":focus-visible": "0 1px 2px 0 rgb(0 0 0 / .05), 0 0 0 2px oklch(70.8% 0 0 / .25)",      ':is(.dark *, [data-theme="dark"] *)':        "0 1px 2px 0 rgb(0 0 0 / .05), 0 0 0 1px rgb(255 255 255 / .1)",      ':is(.dark *, [data-theme="dark"] *):focus-visible':        "0 1px 2px 0 rgb(0 0 0 / .05), 0 0 0 2px oklch(55.6% 0 0 / .3)",    },    transitionProperty: "box-shadow, border-color",    transitionDuration: "150ms",    "::placeholder": {      color: {        default: "oklch(70.8% 0 0)",        ':is(.dark *, [data-theme="dark"] *)': "oklch(55.6% 0 0)",      },    },  },});export function CustomStyles() {  return (    <TextField xstyle={styles.root} name="email">      <Label xstyle={styles.label}>Email</Label>      <Input type="email" xstyle={styles.input} placeholder="[email protected]" />    </TextField>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

全局 CSS

若要自定义组件类,可使用 @layer components 指令。了解更多。

@layer components {  .textfield {    @apply flex flex-col gap-1;  }
  /* When invalid, the description is hidden automatically */  .textfield[data-invalid="true"] [data-slot="description"],  .textfield[aria-invalid="true"] [data-slot="description"] {    @apply hidden;  }
  /* Description has default padding */  .textfield [data-slot="description"] {    @apply px-1;  }}

样式参考

HeroUI 遵循 BEM 方法论,确保组件变体与状态可复用且易于自定义。

CSS 类

  • .textfield – 根容器,样式极少(flex flex-col gap-1)

提示: 子组件(Label、Input、TextArea、Description、FieldError)各自拥有 CSS 类与样式,定制方式请参见对应文档。

交互状态

TextField 会根据状态自动管理以下 data 属性:

  • 无效:[data-invalid="true"] 或 [aria-invalid="true"] — 无效时自动隐藏 description 插槽
  • 禁用:[data-disabled="true"] — 在 isDisabled 为 true 时应用
  • 焦点在内部:[data-focus-within="true"] — 任一子级 input 聚焦时应用
  • 可见焦点:[data-focus-visible="true"] — 键盘导航产生可见焦点时应用

更多属性可通过 render prop 获取(见下文 TextFieldRenderProps)。

API 参考

TextField

继承 React Aria TextField 的全部 props。

Base Props

Prop类型默认值描述
childrenReact.ReactNode | (values: TextFieldRenderProps) => React.ReactNode-子组件(Label、Input 等)或渲染函数。
classNamestring | (values: TextFieldRenderProps) => string-用于样式的 CSS 类,支持渲染 prop。
styleReact.CSSProperties | (values: TextFieldRenderProps) => React.CSSProperties-行内样式,支持渲染 prop。
fullWidthbooleanfalseTextField 是否占满容器宽度。
idstring-元素的唯一 id。
renderDOMRenderFunction<keyof React.JSX.IntrinsicElements, TextFieldRenderProps>-使用自定义渲染函数覆盖默认 DOM 元素。

Validation Props

Prop类型默认值描述
isRequiredbooleanfalse提交表单前是否必须填写。
isInvalidboolean-当前值是否无效。
validate(value: string) => ValidationError | true | null | undefined-自定义校验函数。
validationBehavior'native' | 'aria''native'使用原生 HTML 表单校验还是 ARIA 属性。
validationErrorsstring[]-服务端校验错误。

Value Props

Prop类型默认值描述
valuestring-当前值(受控)。
defaultValuestring-默认值(非受控)。
onChange(value: string) => void-值变化时调用的事件处理函数。

State Props

Prop类型默认值描述
isDisabledboolean-是否禁用输入。
isReadOnlyboolean-是否可选中但不可修改。

Form Props

Prop类型默认值描述
namestring-用于 HTML 表单提交的 input 名称。
autoFocusboolean-是否在挂载时自动聚焦。

Accessibility Props

Prop类型默认值描述
aria-labelstring-无可见标签时的无障碍标签。
aria-labelledbystring-用于标注该字段的元素 id。
aria-describedbystring-用于描述该字段的元素 id。
aria-detailsstring-提供附加详情的元素 id。

Composition Components

TextField 与以下独立组件配合使用,请直接按需引入并组合:

  • Label — @lenso/ui 的字段标签组件
  • Input — @lenso/ui 的单行文本输入
  • TextArea — @lenso/ui 的多行文本输入
  • Description — @lenso/ui 的辅助说明组件
  • FieldError — @lenso/ui 的校验错误信息组件

这些组件各自有独立的 props API,请在 TextField 内直接使用:

<TextField isRequired isInvalid={hasError}>  <Label>Email Address</Label>  <Input type="email" value={email} onChange={(e) => setEmail(e.target.value)} />  <Description>We'll never share your email.</Description>  <FieldError>Please enter a valid email address.</FieldError></TextField>

TextFieldRenderProps

对 className、style 或 children 使用渲染 prop 时,可使用以下值:

Prop类型描述
isDisabledboolean字段是否禁用。
isInvalidboolean字段当前是否无效。
isReadOnlyboolean字段是否只读。
isRequiredboolean字段是否必填。
isFocusedboolean字段是否聚焦(已弃用 — 请使用 isFocusWithin)。
isFocusWithinboolean是否有任一子元素聚焦。
isFocusVisibleboolean是否为可见键盘焦点。

相关案例

See upstream TextField showcases. Product showcases are not part of the local component runtime.

相关组件