Files
skillhub-098-shadcn/rules/forms.md
T
2026-07-13 21:36:22 +08:00

193 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 表单与输入
## 目录
- 表单使用 FieldGroup + Field
- InputGroup 需配合 InputGroupInput/InputGroupTextarea
- 输入框内的按钮使用 InputGroup + InputGroupAddon
- 选项集合(2–7 个选项)使用 ToggleGroup
- FieldSet + FieldLegend 用于对相关字段进行分组
- 字段校验与禁用状态
---
## 表单使用 FieldGroup + Field
始终使用 `FieldGroup` + `Field` —— 切勿使用 `space-y-*` 的原始 `div`
```tsx
<FieldGroup>
<Field>
<FieldLabel htmlFor="email">邮箱</FieldLabel>
<Input id="email" type="email" />
</Field>
<Field>
<FieldLabel htmlFor="password">密码</FieldLabel>
<Input id="password" type="password" />
</Field>
</FieldGroup>
```
在设置页面中使用 `Field orientation="horizontal"`。对于视觉上隐藏的标签,使用 `FieldLabel className="sr-only"`
**选择表单控件:**
- 简单文本输入 → `Input`
- 带预定义选项的下拉框 → `Select`
- 可搜索下拉框 → `Combobox`
- 原生 HTML 选择(无 JS)→ `native-select`
- 布尔切换 → `Switch`(用于设置)或 `Checkbox`(用于表单)
- 少数选项中的单选 → `RadioGroup`
- 在 25 个选项之间切换 → `ToggleGroup` + `ToggleGroupItem`
- OTP/验证码 → `InputOTP`
- 多行文本 → `Textarea`
---
## InputGroup 需配合 InputGroupInput/InputGroupTextarea
切勿在 `InputGroup` 内部使用原始的 `Input``Textarea`
**错误示例:**
```tsx
<InputGroup>
<Input placeholder="搜索..." />
</InputGroup>
```
**正确示例:**
```tsx
import { InputGroup, InputGroupInput } from "@/components/ui/input-group"
<InputGroup>
<InputGroupInput placeholder="搜索..." />
</InputGroup>
```
---
## 输入框内的按钮使用 InputGroup + InputGroupAddon
切勿通过自定义定位将 `Button` 直接放在 `Input` 内部或紧邻其旁。
**错误示例:**
```tsx
<div className="relative">
<Input placeholder="搜索..." className="pr-10" />
<Button className="absolute right-0 top-0" size="icon">
<SearchIcon />
</Button>
</div>
```
**正确示例:**
```tsx
import { InputGroup, InputGroupInput, InputGroupAddon } from "@/components/ui/input-group"
<InputGroup>
<InputGroupInput placeholder="搜索..." />
<InputGroupAddon>
<Button size="icon">
<SearchIcon data-icon="inline-start" />
</Button>
</InputGroupAddon>
</InputGroup>
```
---
## 选项集合(27 个选项)使用 ToggleGroup
不要手动循环 `Button` 组件并自行管理激活状态。
**错误示例:**
```tsx
const [selected, setSelected] = useState("daily")
<div className="flex gap-2">
{["daily", "weekly", "monthly"].map((option) => (
<Button
key={option}
variant={selected === option ? "default" : "outline"}
onClick={() => setSelected(option)}
>
{option}
</Button>
))}
</div>
```
**正确示例:**
```tsx
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
<ToggleGroup spacing={2}>
<ToggleGroupItem value="daily">每日</ToggleGroupItem>
<ToggleGroupItem value="weekly">每周</ToggleGroupItem>
<ToggleGroupItem value="monthly">每月</ToggleGroupItem>
</ToggleGroup>
```
结合 `Field` 使用,创建带标签的切换组:
```tsx
<Field orientation="horizontal">
<FieldTitle id="theme-label">主题</FieldTitle>
<ToggleGroup aria-labelledby="theme-label" spacing={2}>
<ToggleGroupItem value="light">浅色</ToggleGroupItem>
<ToggleGroupItem value="dark">深色</ToggleGroupItem>
<ToggleGroupItem value="system">跟随系统</ToggleGroupItem>
</ToggleGroup>
</Field>
```
> **注意:** `defaultValue` 和 `type`/`multiple` 属性在 base 与 radix 之间存在差异。详见 [base-vs-radix.md](./base-vs-radix.md#togglegroup)。
---
## FieldSet + FieldLegend 用于对相关字段进行分组
对相关的复选框、单选按钮或开关,使用 `FieldSet` + `FieldLegend` —— 而不是在 `div` 中加一个标题:
```tsx
<FieldSet>
<FieldLegend variant="label">偏好设置</FieldLegend>
<FieldDescription>请选择所有适用的选项。</FieldDescription>
<FieldGroup className="gap-3">
<Field orientation="horizontal">
<Checkbox id="dark" />
<FieldLabel htmlFor="dark" className="font-normal">深色模式</FieldLabel>
</Field>
</FieldGroup>
</FieldSet>
```
---
## 字段校验与禁用状态
两个属性都需要 —— `data-invalid`/`data-disabled` 用于设置字段的样式(标签、描述),而 `aria-invalid`/`disabled` 用于设置控件的样式。
```tsx
// 无效状态
<Field data-invalid>
<FieldLabel htmlFor="email">邮箱</FieldLabel>
<Input id="email" aria-invalid />
<FieldDescription>邮箱地址无效。</FieldDescription>
</Field>
// 禁用状态
<Field data-disabled>
<FieldLabel htmlFor="email">邮箱</FieldLabel>
<Input id="email" disabled />
</Field>
```
适用于所有控件:`Input``Textarea``Select``Checkbox``RadioGroupItem``Switch``Slider``NativeSelect``InputOTP`