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>)示例
表面样式
在 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.
文本域
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"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 | 类型 | 默认值 | 描述 |
|---|---|---|---|
children | React.ReactNode | (values: TextFieldRenderProps) => React.ReactNode | - | 子组件(Label、Input 等)或渲染函数。 |
className | string | (values: TextFieldRenderProps) => string | - | 用于样式的 CSS 类,支持渲染 prop。 |
style | React.CSSProperties | (values: TextFieldRenderProps) => React.CSSProperties | - | 行内样式,支持渲染 prop。 |
fullWidth | boolean | false | TextField 是否占满容器宽度。 |
id | string | - | 元素的唯一 id。 |
render | DOMRenderFunction<keyof React.JSX.IntrinsicElements, TextFieldRenderProps> | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
Validation Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
isRequired | boolean | false | 提交表单前是否必须填写。 |
isInvalid | boolean | - | 当前值是否无效。 |
validate | (value: string) => ValidationError | true | null | undefined | - | 自定义校验函数。 |
validationBehavior | 'native' | 'aria' | 'native' | 使用原生 HTML 表单校验还是 ARIA 属性。 |
validationErrors | string[] | - | 服务端校验错误。 |
Value Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
value | string | - | 当前值(受控)。 |
defaultValue | string | - | 默认值(非受控)。 |
onChange | (value: string) => void | - | 值变化时调用的事件处理函数。 |
State Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
isDisabled | boolean | - | 是否禁用输入。 |
isReadOnly | boolean | - | 是否可选中但不可修改。 |
Form Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
name | string | - | 用于 HTML 表单提交的 input 名称。 |
autoFocus | boolean | - | 是否在挂载时自动聚焦。 |
Accessibility Props
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
aria-label | string | - | 无可见标签时的无障碍标签。 |
aria-labelledby | string | - | 用于标注该字段的元素 id。 |
aria-describedby | string | - | 用于描述该字段的元素 id。 |
aria-details | string | - | 提供附加详情的元素 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 | 类型 | 描述 |
|---|---|---|
isDisabled | boolean | 字段是否禁用。 |
isInvalid | boolean | 字段当前是否无效。 |
isReadOnly | boolean | 字段是否只读。 |
isRequired | boolean | 字段是否必填。 |
isFocused | boolean | 字段是否聚焦(已弃用 — 请使用 isFocusWithin)。 |
isFocusWithin | boolean | 是否有任一子元素聚焦。 |
isFocusVisible | boolean | 是否为可见键盘焦点。 |
相关案例
See upstream TextField showcases. Product showcases are not part of the local component runtime.