表单字段 · Field
表单字段用于表单输入场景。下面的官方示例展示原生用法与状态,属性名保持上游 API。
安装与前置条件
npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0
需要 React 19+,按顺序导入基础 CSS 和主题,并设置 Theme Provider。参见开始使用。
示例与使用方式
- 表单字段 · 综合展示 1:首先体验这个示例,再查看代码理解组件的组合方式。
- 表单字段 · 综合展示 2:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 表单字段 · 基础用法 3:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 表单字段 · 交互示例 4:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 表单字段 · 样式变化 / 状态 / 样式 5:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 表单字段 · 交互示例 6:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
API 与上游详细参考
优先使用 0.7.1 官方中文说明;上游尚未提供中文的条目保留英文。属性名、类型及默认值保持原生 API,不把示例状态名称当成组件属性。
Field
Field is a low-level wrapper for custom, native, or third-party controls that do not already provide field label, description, and status UI. Use it when you need the Field shell around a control you own; use styled Astryx inputs like TextInput, Typeahead, and Select directly when they already expose label, description, and validation props.
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| label * | string | Label text for the field (always rendered for accessibility). | |
| inputID * | string | ID for the input element (used for the label htmlFor attribute). | |
| labelID | string | ID applied to the label element itself for group accessibility. | |
| isGroupLabel | boolean | false | Renders the label as a span for control groups (radiogroup, checkbox list). |
| children * | ReactNode | The input or control to render. | |
| isLabelHidden | boolean | false | Visually hide the label (still accessible to screen readers). |
| isDisabled | boolean | false | Whether the associated input is disabled. Propagates disabled styling to the label. |
| description | string | Description text displayed between the label and input. | |
| descriptionID | string | ID for the description element (use for aria-describedby on the input). | |
| isOptional | boolean | false | Whether the field is optional (mutually exclusive with isRequired). |
| isRequired | boolean | false | Whether the field is required (mutually exclusive with isOptional). |
| labelIcon | IconType | Icon to display before the label text. See astryx docs icons for valid semantic names. | |
| labelTooltip | string | Tooltip text to display in an info icon at the end of the label. | |
| status | {type: 'warning' | 'error' | 'success', message?: string, messageID?: string} | Status indicator with type and optional message. When message is set, displays a colored status box. messageID is for wiring aria-describedby on the input. | |
| statusVariant | 'attached' | 'detached' | 'attached' | How the status message renders relative to the input. Attached overlaps the input border; detached floats below. |
| width | SizeValue | Width of the field (number = pixels, string used as-is, e.g. "100%"). Sizes the whole field (label, control, and status) so they stay aligned. Prefer this over setting width via xstyle/className/style, which only size the inner control box. Without a width, a row can shrink the whole field below the natural width of its control, so filter bars shrink instead of overflowing. | |
| ref | React.Ref<HTMLDivElement> | Ref forwarded to the root element. | |
| xstyle | StyleXStyles | StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value: not an inline style object like style={{}}. | |
| className | string | CSS class name(s) appended to the root element. Prefer xstyle for StyleX deduplication. | |
| style | React.CSSProperties | Inline styles applied to the root element. Takes priority over StyleX inline styles. |
使用建议
- Wrap custom controls, native inputs, or third-party widgets that need labeling, helper text, optional/required indicators, or validation status.
- Always provide a label for accessibility, even if visually hidden with isLabelHidden.
- Use inputID and descriptionID to connect the label and description to the inner control with htmlFor and aria-describedby.
- 避免:Nest Field around styled inputs such as TextInput, Typeahead, Select, DateInput, or TextArea; those components already render their own Field shell.
- 避免:Use the attached status variant on non-bordered controls such as sliders, switches, or checkboxes; use detached so the message does not overlap the control.
- 避免:Set both isOptional and isRequired on the same field.
- 避免:Hide the label without providing an alternative way for the user to understand the field purpose.
Filter bar
import {useState} from 'react';
import {HStack} from '@astryxdesign/core/HStack';
import {Icon} from '@astryxdesign/core/Icon';
import {Selector} from '@astryxdesign/core/Selector';
import {StackItem} from '@astryxdesign/core/Stack';
import {TextInput} from '@astryxdesign/core/TextInput';
// Every Field-based input (TextInput, Selector, DateInput, ...) can be shrunk
// by its row, so a filter bar never pushes the page sideways. Let the row wrap
// so that on a phone the search box keeps a full line and the selectors move
// below it; on wider screens everything stays on one line, with the search box
// taking the free space.
function OrdersFilterBar() {
const [query, setQuery] = useState('');
const [status, setStatus] = useState('Awaiting fulfillment');
const [region, setRegion] = useState('All regions');
const [sort, setSort] = useState('Newest first');
return (
<HStack gap={2} wrap="wrap" vAlign="center">
<StackItem size="fill">
<TextInput
label="Search orders"
isLabelHidden
placeholder="Search by order or customer"
startIcon={<Icon icon="search" />}
value={query}
onChange={setQuery}
/>
</StackItem>
<Selector
label="Status"
isLabelHidden
options={['All statuses', 'Awaiting fulfillment', 'Shipped', 'Delivered', 'Returned']}
value={status}
onChange={setStatus}
/>
<Selector
label="Region"
isLabelHidden
options={['All regions', 'North America', 'Europe', 'Asia Pacific']}
value={region}
onChange={setRegion}
/>
<Selector
label="Sort"
isLabelHidden
options={['Newest first', 'Oldest first', 'Highest total']}
value={sort}
onChange={setSort}
/>
</HStack>
);
}
Wrap a custom control
function CustomSliderField() {
return (
<Field
label="Confidence"
inputID="confidence-slider"
description="Choose how strict the review should be."
descriptionID="confidence-help"
status={{type: 'success', message: 'Recommended default'}}
statusVariant="detached">
<input
id="confidence-slider"
type="range"
min={0}
max={100}
defaultValue={60}
aria-describedby="confidence-help"
/>
</Field>
);
}
主题 API
{
"targets": [
{
"className": "astryx-field",
"visualProps": [
"layout"
]
},
{
"className": "astryx-field-label"
},
{
"className": "astryx-field-status",
"visualProps": [
"type",
"variant"
]
},
{
"className": "astryx-input-status-icon",
"visualProps": [
"size",
"status"
]
},
{
"className": "astryx-input-clear-button"
},
{
"className": "astryx-input-clear-icon"
}
],
"vars": [
{
"name": "--_field-radius",
"description": "Border radius of input fields",
"default": "var(--radius-element)",
"private": true
},
{
"name": "--_field-status-overlap",
"description": "Amount an attached FieldStatus extends behind the lower half of the control. Set from the rendered control size.",
"default": "calc(var(--size-element-md) / 2)",
"private": true
},
{
"name": "--_input-clear-hit-inset",
"description": "Outset of the clear (✕) button's invisible hit area, applied to a ::after overlay. 0 on a fine pointer; negative on a coarse one, which grows the 20px button to the 24px touch target without changing what is drawn.",
"default": "0px",
"private": true
},
{
"name": "--_input-clear-hit-content",
"description": "Whether the clear (✕) button's invisible hit overlay exists. `none` on a fine pointer, so no ::after is generated and hover still reaches the glyph; `\"\"` on a coarse one, where the overlay provides the 24px touch target.",
"default": "none",
"private": true
}
],
"derived": [
{
"property": "borderRadius",
"vars": [
"--_field-radius"
]
}
]
}
FieldLabel
FieldStatus
组件结构
- Label: Text identifying the field. Always rendered for accessibility, optionally hidden visually.
- Description: Helper text between the label and input explaining what to enter.
- Control slot: A custom, native, or third-party control that does not already render a field shell.
- Status message: Inline validation feedback showing error, warning, or success with a message.
- Optional/Required indicator: Badge next to the label showing whether the field is optional or required.
- Label tooltip: Info icon at the end of the label with a tooltip explaining the field.
Field Label
独立的标签组件,支持可选/必填指示器和工具提示。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| label * | string | 标签文本。 | |
| inputID * | string | 此标签关联的输入框 ID。 | |
| isLabelHidden | boolean | false | 视觉隐藏标签。 |
| isDisabled | boolean | false | 关联的输入框是否禁用。 |
| isOptional | boolean | false | 显示"Optional"指示器。 |
| isRequired | boolean | false | 显示"Required"指示器。 |
| labelIcon | IconType | 标签文本前的图标。 | |
| labelTooltip | string | 标签末尾信息图标的工具提示文本。 |