Form 表单组件 #
FormControl 表单控件 #
FormControl 是一个包装组件,用于为表单控件提供上下文。
jsx
import {
FormControl,
FormLabel,
FormHelperText,
FormErrorMessage,
Input,
} from '@chakra-ui/react'
function FormExample() {
return (
<FormControl>
<FormLabel>邮箱地址</FormLabel>
<Input type="email" />
<FormHelperText>我们不会分享您的邮箱</FormHelperText>
</FormControl>
)
}
表单状态 #
必填 #
jsx
<FormControl isRequired>
<FormLabel>用户名</FormLabel>
<Input />
</FormControl>
错误 #
jsx
<FormControl isInvalid>
<FormLabel>邮箱</FormLabel>
<Input />
<FormErrorMessage>邮箱格式不正确</FormErrorMessage>
</FormControl>
禁用 #
jsx
<FormControl isDisabled>
<FormLabel>禁用字段</FormLabel>
<Input />
</FormControl>
只读 #
jsx
<FormControl isReadOnly>
<FormLabel>只读字段</FormLabel>
<Input />
</FormControl>
完整表单示例 #
登录表单 #
jsx
function LoginForm() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [errors, setErrors] = useState({})
const validateForm = () => {
const newErrors = {}
if (!email) newErrors.email = '邮箱不能为空'
if (!password) newErrors.password = '密码不能为空'
setErrors(newErrors)
return Object.keys(newErrors).length === 0
}
const handleSubmit = (e) => {
e.preventDefault()
if (validateForm()) {
console.log('提交成功', { email, password })
}
}
return (
<Box as="form" onSubmit={handleSubmit} w="100%" maxW="400px">
<VStack spacing={4}>
<FormControl isInvalid={errors.email}>
<FormLabel>邮箱</FormLabel>
<Input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<FormErrorMessage>{errors.email}</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.password}>
<FormLabel>密码</FormLabel>
<Input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<FormErrorMessage>{errors.password}</FormErrorMessage>
</FormControl>
<Button type="submit" colorScheme="blue" w="full">
登录
</Button>
</VStack>
</Box>
)
}
注册表单 #
jsx
function RegisterForm() {
const [formData, setFormData] = useState({
username: '',
email: '',
password: '',
confirmPassword: '',
})
const [errors, setErrors] = useState({})
const handleChange = (field) => (e) => {
setFormData({ ...formData, [field]: e.target.value })
}
const validateForm = () => {
const newErrors = {}
if (!formData.username) newErrors.username = '用户名不能为空'
if (!formData.email) newErrors.email = '邮箱不能为空'
if (formData.password.length < 6) newErrors.password = '密码至少 6 位'
if (formData.password !== formData.confirmPassword) {
newErrors.confirmPassword = '两次密码不一致'
}
setErrors(newErrors)
return Object.keys(newErrors).length === 0
}
const handleSubmit = (e) => {
e.preventDefault()
if (validateForm()) {
console.log('注册成功', formData)
}
}
return (
<Box as="form" onSubmit={handleSubmit} w="100%" maxW="400px">
<VStack spacing={4}>
<FormControl isInvalid={errors.username}>
<FormLabel>用户名</FormLabel>
<Input
value={formData.username}
onChange={handleChange('username')}
/>
<FormErrorMessage>{errors.username}</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.email}>
<FormLabel>邮箱</FormLabel>
<Input
type="email"
value={formData.email}
onChange={handleChange('email')}
/>
<FormErrorMessage>{errors.email}</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.password}>
<FormLabel>密码</FormLabel>
<Input
type="password"
value={formData.password}
onChange={handleChange('password')}
/>
<FormErrorMessage>{errors.password}</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.confirmPassword}>
<FormLabel>确认密码</FormLabel>
<Input
type="password"
value={formData.confirmPassword}
onChange={handleChange('confirmPassword')}
/>
<FormErrorMessage>{errors.confirmPassword}</FormErrorMessage>
</FormControl>
<Button type="submit" colorScheme="blue" w="full">
注册
</Button>
</VStack>
</Box>
)
}
联系表单 #
jsx
function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
subject: '',
message: '',
})
const handleSubmit = (e) => {
e.preventDefault()
console.log('提交', formData)
}
return (
<Box as="form" onSubmit={handleSubmit} w="100%" maxW="500px">
<VStack spacing={4}>
<SimpleGrid columns={2} spacing={4} w="full">
<FormControl isRequired>
<FormLabel>姓名</FormLabel>
<Input
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
/>
</FormControl>
<FormControl isRequired>
<FormLabel>邮箱</FormLabel>
<Input
type="email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
/>
</FormControl>
</SimpleGrid>
<FormControl isRequired>
<FormLabel>主题</FormLabel>
<Input
value={formData.subject}
onChange={(e) => setFormData({ ...formData, subject: e.target.value })}
/>
</FormControl>
<FormControl isRequired>
<FormLabel>消息</FormLabel>
<Textarea
rows={5}
value={formData.message}
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
/>
</FormControl>
<Button type="submit" colorScheme="blue" w="full">
发送消息
</Button>
</VStack>
</Box>
)
}
设置表单 #
jsx
function SettingsForm() {
const [settings, setSettings] = useState({
notifications: true,
emailUpdates: false,
language: 'zh',
theme: 'light',
})
return (
<VStack spacing={6} align="stretch">
<Heading size="md">通知设置</Heading>
<FormControl display="flex" alignItems="center" justifyContent="space-between">
<Box>
<Text fontWeight="medium">推送通知</Text>
<Text fontSize="sm" color="gray.500">接收应用推送通知</Text>
</Box>
<Switch
isChecked={settings.notifications}
onChange={(e) => setSettings({ ...settings, notifications: e.target.checked })}
/>
</FormControl>
<FormControl display="flex" alignItems="center" justifyContent="space-between">
<Box>
<Text fontWeight="medium">邮件更新</Text>
<Text fontSize="sm" color="gray.500">接收产品更新邮件</Text>
</Box>
<Switch
isChecked={settings.emailUpdates}
onChange={(e) => setSettings({ ...settings, emailUpdates: e.target.checked })}
/>
</FormControl>
<Divider />
<Heading size="md">偏好设置</Heading>
<FormControl>
<FormLabel>语言</FormLabel>
<Select
value={settings.language}
onChange={(e) => setSettings({ ...settings, language: e.target.value })}
>
<option value="zh">中文</option>
<option value="en">English</option>
<option value="ja">日本語</option>
</Select>
</FormControl>
<FormControl>
<FormLabel>主题</FormLabel>
<RadioGroup
value={settings.theme}
onChange={(value) => setSettings({ ...settings, theme: value })}
>
<HStack spacing={4}>
<Radio value="light">浅色</Radio>
<Radio value="dark">深色</Radio>
<Radio value="system">跟随系统</Radio>
</HStack>
</RadioGroup>
</FormControl>
<Button colorScheme="blue" alignSelf="flex-start">
保存设置
</Button>
</VStack>
)
}
表单布局技巧 #
水平布局 #
jsx
<FormControl as={HStack} spacing={4}>
<FormLabel w="120px">用户名</FormLabel>
<Input flex="1" />
</FormControl>
网格布局 #
jsx
<SimpleGrid columns={2} spacing={4}>
<FormControl>
<FormLabel>姓</FormLabel>
<Input />
</FormControl>
<FormControl>
<FormLabel>名</FormLabel>
<Input />
</FormControl>
</SimpleGrid>
分组表单 #
jsx
<VStack spacing={8} align="stretch">
<Box>
<Heading size="sm" mb={4}>个人信息</Heading>
<VStack spacing={4}>
<FormControl>
<FormLabel>姓名</FormLabel>
<Input />
</FormControl>
<FormControl>
<FormLabel>邮箱</FormLabel>
<Input type="email" />
</FormControl>
</VStack>
</Box>
<Divider />
<Box>
<Heading size="sm" mb={4}>地址信息</Heading>
<VStack spacing={4}>
<FormControl>
<FormLabel>地址</FormLabel>
<Input />
</FormControl>
<SimpleGrid columns={2} spacing={4} w="full">
<FormControl>
<FormLabel>城市</FormLabel>
<Input />
</FormControl>
<FormControl>
<FormLabel>邮编</FormLabel>
<Input />
</FormControl>
</SimpleGrid>
</VStack>
</Box>
</VStack>
FormControl 属性速查表 #
| 属性 | 说明 |
|---|---|
| isRequired | 必填 |
| isInvalid | 无效 |
| isDisabled | 禁用 |
| isReadOnly | 只读 |
下一步 #
现在你已经掌握了 Form 表单组件,接下来学习 Table 表格,了解如何展示数据!
最后更新:2026-03-28