Badge 徽标

把未读数或者短标记钉在宿主元素的角上。

399+NEW
import { Bell, Mail, MessageSquare } from 'lucide-react'
import { Badge, IconButton, Inline } from '@hina-ui/react'

export default function Demo() {
  return (
    <Inline align="center" className="gap-6">
      <Badge content={3}>
        <IconButton label="通知" variant="soft">
          <Bell />
        </IconButton>
      </Badge>
      <Badge content={128} tone="accent">
        <IconButton label="私信" variant="soft">
          <Mail />
        </IconButton>
      </Badge>
      <Badge content="NEW" tone="success" size="md">
        <IconButton label="评论" variant="soft">
          <MessageSquare />
        </IconButton>
      </Badge>
    </Inline>
  )
}
tsx

用法

import { Badge } from '@hina-ui/react'
ts

宿主元素放在 children 中,content 是钉在角上的内容。组件只负责定位与呈现,宿主本身不受影响。角标默认不接收指针事件,覆盖在宿主范围内的区域仍由宿主响应。

55 条未读
import { Bell } from 'lucide-react'
import { Badge, IconButton } from '@hina-ui/react'

export default function Demo() {
  return (
    <Badge content={5} label="5 条未读">
      <IconButton label="通知" variant="soft">
        <Bell />
      </IconButton>
    </Badge>
  )
}
tsx

示例

最大值

content 为数字且超过 max 时显示为上限加号,默认上限为 99。

9999+999+
import { Bell } from 'lucide-react'
import { Badge, IconButton, Inline } from '@hina-ui/react'

export default function Demo() {
  return (
    <Inline align="center" className="gap-6">
      <Badge content={99}>
        <IconButton label="通知" variant="soft">
          <Bell />
        </IconButton>
      </Badge>
      <Badge content={1280}>
        <IconButton label="通知" variant="soft">
          <Bell />
        </IconButton>
      </Badge>
      <Badge content={1280} max={999}>
        <IconButton label="通知" variant="soft">
          <Bell />
        </IconButton>
      </Badge>
    </Inline>
  )
}
tsx

色调

默认为 danger。未读与待办用 danger,一般计数用 accent 或者 neutral,状态提示按语义选择其余三种。

666666
import { Bell } from 'lucide-react'
import { Badge, IconButton, Inline } from '@hina-ui/react'

export default function Demo() {
  return (
    <Inline align="center" className="gap-6">
      {(['danger', 'accent', 'neutral', 'success', 'warning', 'info'] as const).map(tone => (
        <Badge key={tone} content={6} tone={tone}>
          <IconButton label="通知" variant="soft">
            <Bell />
          </IconButton>
        </Badge>
      ))}
    </Inline>
  )
}
tsx

尺寸

两种尺寸的字号相同,区别在于徽标的高度与最小宽度。宿主较大或者内容为文字时使用 md。

88
import { Bell } from 'lucide-react'
import { Badge, IconButton, Inline } from '@hina-ui/react'

export default function Demo() {
  return (
    <Inline align="center" className="gap-6">
      <Badge content={8} size="sm">
        <IconButton label="通知" variant="soft">
          <Bell />
        </IconButton>
      </Badge>
      <Badge content={8} size="md">
        <IconButton label="通知" variant="soft">
          <Bell />
        </IconButton>
      </Badge>
    </Inline>
  )
}
tsx

位置

placement 指定钉在哪个角,共四个取值,默认为右上角。

2222
import { Bell } from 'lucide-react'
import { Badge, IconButton, Inline } from '@hina-ui/react'

export default function Demo() {
  return (
    <Inline align="center" className="gap-6">
      {(['top-end', 'top-start', 'bottom-end', 'bottom-start'] as const).map(placement => (
        <Badge key={placement} content={2} placement={placement}>
          <IconButton label="通知" variant="soft">
            <Bell />
          </IconButton>
        </Badge>
      ))}
    </Inline>
  )
}
tsx

圆形宿主

宿主是圆形时设置 shape="circle",角点向内收拢,徽标贴合圆弧而不是外接矩形的角。

星见书音4

rect

星见书音4

circle

import { Avatar, Badge, Inline, Stack, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Inline align="start" className="gap-8">
      <Stack gap="xs" align="center">
        <Badge content={4}>
          <Avatar size="lg" src="/avatars/peek.webp" alt="星见书音" />
        </Badge>
        <Text tone="muted" size="sm">
          rect
        </Text>
      </Stack>
      <Stack gap="xs" align="center">
        <Badge content={4} shape="circle">
          <Avatar size="lg" src="/avatars/peek.webp" alt="星见书音" />
        </Badge>
        <Text tone="muted" size="sm">
          circle
        </Text>
      </Stack>
    </Inline>
  )
}
tsx

自定义内容

content 也可以传入元素,例如一个图标。此时应当通过 label 提供无障碍名称。

已完成
import { Bookmark, Check } from 'lucide-react'
import { Badge, IconButton } from '@hina-ui/react'

export default function Demo() {
  return (
    <Badge content={<Check className="size-3" />} tone="success" size="md" label="已完成">
      <IconButton label="收藏" variant="soft">
        <Bookmark />
      </IconButton>
    </Badge>
  )
}
tsx

设置 bare 后徽标不绘制底色,也没有内边距,只负责定位与描边,尺寸由 content 决定。把 Indicator 传给 content 即可在头像角上显示状态点。

星见书音在线星离开
import { Avatar, Badge, Indicator, Inline } from '@hina-ui/react'

export default function Demo() {
  return (
    <Inline gap="lg">
      <Badge
        content={<Indicator tone="success" size="lg" />}
        bare
        label="在线"
        placement="bottom-end"
        shape="circle"
      >
        <Avatar src="/avatars/paper.webp" alt="星见书音" />
      </Badge>
      <Badge
        content={<Indicator tone="warning" size="lg" />}
        bare
        label="离开"
        placement="bottom-end"
        shape="circle"
      >
        <Avatar name="星见书音" />
      </Badge>
    </Inline>
  )
}
tsx

描边

outline 默认开启,徽标外侧带一圈与页面底色相同的描边,使它从宿主的边缘切出。宿主颜色较深时可以关闭。

99
import { Bell } from 'lucide-react'
import { Badge, IconButton, Inline } from '@hina-ui/react'

export default function Demo() {
  return (
    <Inline align="center" className="gap-6">
      <Badge content={9}>
        <IconButton label="通知" variant="solid" tone="accent" pill size="lg">
          <Bell />
        </IconButton>
      </Badge>
      <Badge content={9} outline={false}>
        <IconButton label="通知" variant="solid" tone="accent" pill size="lg">
          <Bell />
        </IconButton>
      </Badge>
    </Inline>
  )
}
tsx

出现与消失

content 为 0、空字符串或者未设置时,徽标不渲染。出现与消失都带缩放淡入淡出。

22 条未读
'use client'

import { useState } from 'react'
import { Bell } from 'lucide-react'
import { Badge, Button, IconButton, Inline } from '@hina-ui/react'

export default function Demo() {
  const [count, setCount] = useState(2)

  return (
    <Inline align="center" className="gap-6">
      <Badge content={count} label={`${count} 条未读`}>
        <IconButton label="通知" variant="soft">
          <Bell />
        </IconButton>
      </Badge>
      <Inline align="center">
        <Button
          variant="outline"
          tone="neutral"
          size="sm"
          onClick={() => setCount(Math.max(0, count - 1))}
        >
          减少
        </Button>
        <Button variant="outline" tone="neutral" size="sm" onClick={() => setCount(count + 1)}>
          增加
        </Button>
      </Inline>
    </Inline>
  )
}
tsx

无障碍

  • 徽标里的数字缺少上下文,应当通过 label 补充完整说法,例如“3 条未读”。该文字只供屏幕阅读器读取,不显示在界面上。
  • 组件不改变宿主的语义。宿主是按钮时,它仍然是一个按钮。

API

Props

属性
类型
默认值
说明
content
string | number | null
—
徽标的内容,为空时不渲染
max
number
99
数字内容的显示上限
tone
'danger' | 'accent' | 'neutral' | 'success' | 'warning' | 'info'
'danger'
语义色调
size
'sm' | 'md'
'sm'
尺寸
placement
'top-end' | 'top-start' | 'bottom-end' | 'bottom-start'
'top-end'
钉在哪个角
shape
'rect' | 'circle'
'rect'
宿主的形状
outline
boolean
true
是否描出与页面底色相同的边
bare
boolean
false
是否只定位不画底
label
string
—
供屏幕阅读器读取的完整说法
className
string
—
追加至外层容器的类名

内容属性

属性
说明
children
宿主元素
content
替换徽标的内容