Accordion 折叠列表

多段内容依次展开与收起的折叠列表。

登录后进入创作者中心,选择作品类型并填写资料,提交后进入审核队列。

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
  Card,
  Text,
} from '@hina-ui/react'

export default function Demo() {
  return (
    <Card className="w-full max-w-md">
      <Accordion defaultValue="submit">
        <AccordionItem value="submit">
          <AccordionTrigger>如何投稿</AccordionTrigger>
          <AccordionContent>
            <Text tone="muted" size="sm">
              登录后进入创作者中心,选择作品类型并填写资料,提交后进入审核队列。
            </Text>
          </AccordionContent>
        </AccordionItem>
        <AccordionItem value="review">
          <AccordionTrigger>审核需要多久</AccordionTrigger>
          <AccordionContent>
            <Text tone="muted" size="sm">
              通常在三个工作日内完成,资料不全时会退回补充。
            </Text>
          </AccordionContent>
        </AccordionItem>
        <AccordionItem value="edit">
          <AccordionTrigger>可以修改已发布的内容吗</AccordionTrigger>
          <AccordionContent>
            <Text tone="muted" size="sm">
              可以。修改会生成新的版本,经审核后替换当前内容。
            </Text>
          </AccordionContent>
        </AccordionItem>
      </Accordion>
    </Card>
  )
}
tsx

用法

import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@hina-ui/react'
ts

组件由四部分构成:Accordion 持有展开状态,AccordionItem 是一段内容,AccordionTrigger 是该段的标题与切换控件,AccordionContent 是被折叠的正文。每一段以 value 标识。

默认一次只展开一段,点击另一段时当前段收起。触发器自带随开合旋转的指示物。

import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Accordion className="w-full max-w-md">
      <AccordionItem value="intro">
        <AccordionTrigger>作品简介</AccordionTrigger>
        <AccordionContent>
          <Text tone="muted" size="sm">
            转学第一天,我在天台遇见了那个抱着旧相机的少女。
          </Text>
        </AccordionContent>
      </AccordionItem>
      <AccordionItem value="staff">
        <AccordionTrigger>制作人员</AccordionTrigger>
        <AccordionContent>
          <Text tone="muted" size="sm">
            原作、脚本与原画均由同一位作者完成。
          </Text>
        </AccordionContent>
      </AccordionItem>
    </Accordion>
  )
}
tsx

只有一处内容需要折叠时使用 Collapsible。

示例

允许全部收起

默认展开的一段不能再次点击收起。设置 collapsible 后可以收起当前段,列表可以处于全部收起的状态。defaultValue 指定初始展开的段。

转学第一天,我在天台遇见了那个抱着旧相机的少女。

import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Accordion collapsible defaultValue="intro" className="w-full max-w-md">
      <AccordionItem value="intro">
        <AccordionTrigger>作品简介</AccordionTrigger>
        <AccordionContent>
          <Text tone="muted" size="sm">
            转学第一天,我在天台遇见了那个抱着旧相机的少女。
          </Text>
        </AccordionContent>
      </AccordionItem>
      <AccordionItem value="staff">
        <AccordionTrigger>制作人员</AccordionTrigger>
        <AccordionContent>
          <Text tone="muted" size="sm">
            原作、脚本与原画均由同一位作者完成。
          </Text>
        </AccordionContent>
      </AccordionItem>
    </Accordion>
  )
}
tsx

多段同时展开

type 设为 multiple 后各段独立开合,value / onValueChange 与 defaultValue 的值为数组。

转学第一天,我在天台遇见了那个抱着旧相机的少女。

原作、脚本与原画均由同一位作者完成。

import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Accordion type="multiple" defaultValue={['intro', 'staff']} className="w-full max-w-md">
      <AccordionItem value="intro">
        <AccordionTrigger>作品简介</AccordionTrigger>
        <AccordionContent>
          <Text tone="muted" size="sm">
            转学第一天,我在天台遇见了那个抱着旧相机的少女。
          </Text>
        </AccordionContent>
      </AccordionItem>
      <AccordionItem value="staff">
        <AccordionTrigger>制作人员</AccordionTrigger>
        <AccordionContent>
          <Text tone="muted" size="sm">
            原作、脚本与原画均由同一位作者完成。
          </Text>
        </AccordionContent>
      </AccordionItem>
      <AccordionItem value="release">
        <AccordionTrigger>发售信息</AccordionTrigger>
        <AccordionContent>
          <Text tone="muted" size="sm">
            2024 年冬季发售,支持简体中文。
          </Text>
        </AccordionContent>
      </AccordionItem>
    </Accordion>
  )
}
tsx

受控

value / onValueChange 将展开状态交由外部持有,页面上的其他控件也可以切换展开的段。

转学第一天,我在天台遇见了那个抱着旧相机的少女。

'use client'

import { useState } from 'react'
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
  Button,
  Inline,
  Stack,
  Text,
  type AccordionProps,
} from '@hina-ui/react'

export default function Demo() {
  const [open, setOpen] = useState<AccordionProps['value']>('intro')

  return (
    <Stack className="w-full max-w-md">
      <Inline>
        <Button size="sm" variant="soft" tone="neutral" onClick={() => setOpen('intro')}>
          看简介
        </Button>
        <Button size="sm" variant="soft" tone="neutral" onClick={() => setOpen('staff')}>
          看制作人员
        </Button>
      </Inline>
      <Accordion value={open} onValueChange={setOpen}>
        <AccordionItem value="intro">
          <AccordionTrigger>作品简介</AccordionTrigger>
          <AccordionContent>
            <Text tone="muted" size="sm">
              转学第一天,我在天台遇见了那个抱着旧相机的少女。
            </Text>
          </AccordionContent>
        </AccordionItem>
        <AccordionItem value="staff">
          <AccordionTrigger>制作人员</AccordionTrigger>
          <AccordionContent>
            <Text tone="muted" size="sm">
              原作、脚本与原画均由同一位作者完成。
            </Text>
          </AccordionContent>
        </AccordionItem>
      </Accordion>
    </Stack>
  )
}
tsx

禁用

AccordionItem 的 disabled 禁用单段,Accordion 的 disabled 禁用整组。

转学第一天,我在天台遇见了那个抱着旧相机的少女。

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
  Stack,
  Text,
} from '@hina-ui/react'

export default function Demo() {
  return (
    <Stack gap="lg" className="w-full max-w-md">
      <Accordion defaultValue="intro">
        <AccordionItem value="intro">
          <AccordionTrigger>作品简介</AccordionTrigger>
          <AccordionContent>
            <Text tone="muted" size="sm">
              转学第一天,我在天台遇见了那个抱着旧相机的少女。
            </Text>
          </AccordionContent>
        </AccordionItem>
        <AccordionItem value="staff" disabled>
          <AccordionTrigger>制作人员</AccordionTrigger>
          <AccordionContent>
            <Text tone="muted" size="sm">
              原作、脚本与原画均由同一位作者完成。
            </Text>
          </AccordionContent>
        </AccordionItem>
      </Accordion>
      <Accordion disabled>
        <AccordionItem value="intro">
          <AccordionTrigger>作品简介</AccordionTrigger>
          <AccordionContent>
            <Text tone="muted" size="sm">
              转学第一天,我在天台遇见了那个抱着旧相机的少女。
            </Text>
          </AccordionContent>
        </AccordionItem>
        <AccordionItem value="staff">
          <AccordionTrigger>制作人员</AccordionTrigger>
          <AccordionContent>
            <Text tone="muted" size="sm">
              原作、脚本与原画均由同一位作者完成。
            </Text>
          </AccordionContent>
        </AccordionItem>
      </Accordion>
    </Stack>
  )
}
tsx

标题层级

触发器渲染在标题元素内,默认为 h3。level 可以改为其他层级,以符合页面的标题结构。

常见问题

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
  Heading,
  Stack,
  Text,
} from '@hina-ui/react'

export default function Demo() {
  return (
    <Stack className="w-full max-w-md">
      <Heading level={3} size="md">
        常见问题
      </Heading>
      <Accordion>
        <AccordionItem value="submit">
          <AccordionTrigger level={4}>如何投稿</AccordionTrigger>
          <AccordionContent>
            <Text tone="muted" size="sm">
              登录后进入创作者中心,选择作品类型并填写资料。
            </Text>
          </AccordionContent>
        </AccordionItem>
        <AccordionItem value="review">
          <AccordionTrigger level={4}>审核需要多久</AccordionTrigger>
          <AccordionContent>
            <Text tone="muted" size="sm">
              通常在三个工作日内完成。
            </Text>
          </AccordionContent>
        </AccordionItem>
      </Accordion>
    </Stack>
  )
}
tsx

更换指示物

icon 属性仅替换指示物的字形,旋转仍由组件负责;将 icon 设为 false 则不显示指示物。

import { Plus } from 'lucide-react'
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Accordion className="w-full max-w-md">
      <AccordionItem value="intro">
        <AccordionTrigger icon={<Plus />}>作品简介</AccordionTrigger>
        <AccordionContent>
          <Text tone="muted" size="sm">
            转学第一天,我在天台遇见了那个抱着旧相机的少女。
          </Text>
        </AccordionContent>
      </AccordionItem>
      <AccordionItem value="staff">
        <AccordionTrigger icon={false}>制作人员</AccordionTrigger>
        <AccordionContent>
          <Text tone="muted" size="sm">
            原作、脚本与原画均由同一位作者完成。
          </Text>
        </AccordionContent>
      </AccordionItem>
    </Accordion>
  )
}
tsx

行为

  • 展开与收起时内容区的高度随之变化,两个方向使用同一组过渡参数。
  • 收起时内容从无障碍树中移除,键盘焦点不会进入其中。
  • 各段之间以细线分隔。组件本身没有底色与边框,需要卡片外观时放入 Card。

无障碍

  • 触发器是标题中的按钮,带 aria-expanded 与 aria-controls。
  • 上下方向键在触发器之间移动焦点,Home 与 End 跳到首尾。
  • 内容区带 region 角色,屏幕阅读器按区域朗读。

API

Accordion

属性
类型
默认值
说明
type
'single' | 'multiple'
'single'
一次展开一段或者多段
collapsible
boolean
false
single 模式下是否允许全部收起
value
string | string[]
—
展开的段,可受控
defaultValue
string | string[]
—
初始展开的段
disabled
boolean
false
是否禁用整组
className
string
—
追加至根元素的类名
回调
参数
说明
onValueChange
value: string | string[]
展开的段变化

AccordionItem

属性
类型
默认值
说明
value
string
—
该段的标识,必填
disabled
boolean
false
是否禁用该段
className
string
—
追加至该段的类名

AccordionTrigger

属性
类型
默认值
说明
level
2 | 3 | 4 | 5 | 6
3
标题层级
icon
boolean
true
是否显示展开指示物
className
string
—
追加至触发器的类名
属性
说明
children
触发器的文字
icon
替换指示物的字形

AccordionContent

属性
类型
默认值
说明
className
string
—
追加至内容区的类名