# 表单字段 · Field

- 页面: https://jiguang132.com/zh/resources/astryx/docs/field
- 资源: Astryx (https://jiguang132.com/zh/resources/astryx.md)
- 全部指南: https://jiguang132.com/zh/resources/astryx/docs.md

表单字段用于表单输入场景。下面的官方示例展示原生用法与状态，属性名保持上游 API。

## 安装与前置条件

```bash
npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0
```

需要 React 19+，按顺序导入基础 CSS 和主题，并设置 Theme Provider。参见[开始使用](/resources/astryx/docs/getting-started)。

## 示例与使用方式

- **表单字段 · 综合展示 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

```tsx
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

```tsx
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

```json
{
  "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 |  | 标签末尾信息图标的工具提示文本。 |

---

JGuang 全部资源索引: https://jiguang132.com/llms.txt
