'use client'
import { useState } from 'react'
import { Switch } from '@hina-ui/react'
export default function Demo() {
const [autoplay, setAutoplay] = useState(true)
return (
<Switch checked={autoplay} onCheckedChange={setAutoplay}>
自动播放下一话
</Switch>
)
}
tsx
用法
import { Switch } from '@hina-ui/react'
ts
开关表示一个立即生效的设置,与需要提交的复选框不同。checked / onCheckedChange 绑定布尔值,children 是文字,点文字与点轨道都会切换。未声明的属性都会传给内部的轨道元素。
当前值:false
'use client'
import { useState } from 'react'
import { Stack, Switch, Text } from '@hina-ui/react'
export default function Demo() {
const [nsfw, setNsfw] = useState(false)
return (
<Stack gap="sm">
<Switch checked={nsfw} onCheckedChange={setNsfw}>
显示限制级内容
</Switch>
<Text size="sm" tone="muted">
当前值:{String(nsfw)}
</Text>
</Stack>
)
}
tsx
示例
描述
description 在文字下方补一行说明,字号比文字小一档。
'use client'
import { useState } from 'react'
import { Switch } from '@hina-ui/react'
export default function Demo() {
const [sync, setSync] = useState(true)
return (
<Switch
checked={sync}
onCheckedChange={setSync}
description="在其他设备上打开同一部作品时,从上次的位置继续。"
>
同步阅读进度
</Switch>
)
}
tsx
设置行
使用 controlPlacement="end" 将控件放到文案末端,配合 block 撑满容器宽度。说明始终位于标题下方;start 和 end 会跟随文字方向。
'use client'
import { useState } from 'react'
import { Switch } from '@hina-ui/react'
export default function Demo() {
const [sync, setSync] = useState(true)
return (
<Switch
checked={sync}
onCheckedChange={setSync}
controlPlacement="end"
block
description="在其他设备上打开同一部作品时,从上次的位置继续。"
>
同步阅读进度
</Switch>
)
}
tsx
尺寸
size 有 sm、md、lg 三档,轨道高分别为 20、24、28 像素,文字随档位变化。
import { Stack, Switch } from '@hina-ui/react'
export default function Demo() {
return (
<Stack gap="sm">
<Switch size="sm" checked>
小号
</Switch>
<Switch size="md" checked>
中号
</Switch>
<Switch size="lg" checked>
大号
</Switch>
</Stack>
)
}
tsx
状态
invalid 给轨道加上警示色边框;disabled 禁用整个控件。
import { Stack, Switch } from '@hina-ui/react'
export default function Demo() {
return (
<Stack gap="sm">
<Switch invalid>必须开启才能继续</Switch>
<Switch disabled>已禁用</Switch>
<Switch disabled checked>
已禁用且开启
</Switch>
</Stack>
)
}
tsx
仅轨道
没有文字时只渲染轨道,此时必须用 aria-label 命名。
'use client'
import { useState } from 'react'
import { Inline, Switch } from '@hina-ui/react'
export default function Demo() {
const [dark, setDark] = useState(false)
return (
<Inline gap="sm">
<Switch checked={dark} onCheckedChange={setDark} aria-label="深色模式" />
</Inline>
)
}
tsx
在表单中
放进 FormField 后,错误信息由字段渲染并关联到开关;校验规则与提交交给 Form。开关自带文字,字段不必再写标签;它的值常常决定其他字段是否必填,这类规则写在对象层,再指定错误落在哪个字段。
'use client'
import { useState } from 'react'
import * as v from 'valibot'
import { Button, Form, FormField, Input, Switch, Text } from '@hina-ui/react'
const schema = v.pipe(
v.object({
isPublic: v.boolean(),
summary: v.string(),
}),
v.forward(
v.check(input => !input.isPublic || input.summary.trim().length > 0, '公开的作品需要填写简介'),
['summary'],
),
)
export default function Demo() {
const [values, setValues] = useState({ isPublic: true, summary: '' })
const [saved, setSaved] = useState('')
async function save(data: unknown) {
await new Promise(resolve => setTimeout(resolve, 600))
setSaved(JSON.stringify(data))
}
return (
<Form values={values} rules={schema} className="w-80" onSubmit={save}>
{({ submitting }) => (
<>
<FormField name="isPublic">
<Switch
checked={values.isPublic}
onCheckedChange={isPublic => setValues({ ...values, isPublic })}
>
公开显示
</Switch>
</FormField>
<FormField name="summary" label="简介">
<Input
value={values.summary}
onValueChange={summary => setValues({ ...values, summary })}
/>
</FormField>
<Button type="submit" loading={submitting} className="self-start">
保存
</Button>
{saved && (
<Text tone="muted" size="sm">
已保存:{saved}
</Text>
)}
</>
)}
</Form>
)
}
tsx
行为
- 点击文字或者轨道都会切换,拇指滑到另一侧,轨道同时换色。键盘 Tab 落在轨道上,空格切换。
- 悬停整个控件时轨道落墨,按下时加深。
无障碍
- 轨道是
role="switch"的按钮,带aria-checked。根元素是label,文字即名称。 - 没有文字时通过
aria-label或者aria-labelledby命名。 invalid会同时设置aria-invalid。
API
Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
checked | boolean | false | 是否开启 |
size | 'sm' | 'md' | 'lg' | 'md' | 尺寸 |
description | string | — | 文字下方的说明 |
controlPlacement | 'start' | 'end' | 'start' | 控件相对于文案的位置 |
block | boolean | false | 整行撑满容器宽度 |
disabled | boolean | false | 是否禁用 |
invalid | boolean | false | 是否处于校验未通过状态 |
className | string | — | 追加至根元素的类名 |
内容属性
| 属性 | 参数 | 说明 |
|---|---|---|
children | — | 文字 |
回调
| 回调 | 参数 | 说明 |
|---|---|---|
onCheckedChange | value: boolean | 值变化时 |