Badge
17:06Description
Overlays a numeric or dot badge on the top-right corner of a host element. When content is passed through the default slot the component supplies its own positioning anchor and pins the badge to the top-right; with no content it acts as a standalone badge overlaid on a relatively positioned host. A count above overflow-count renders as the cap plus + (e.g. 99+), and a count of 0 is hidden unless show-zero is set.
Compatibility
| Platform | Support |
|---|---|
| App | ✅ Supported |
| H5 | ✅ Supported |
| WeChat Mini Program | ✅ Supported |
Examples
Basic Usage
Pass a number to count; values above the cap render as 99+ according to overflow-count.
View source
<template>
<view class="row">
<ux-badge :count="5" custom-class="badge-item">
<view class="box"><text class="text">消息</text></view>
</ux-badge>
<ux-badge :count="99" custom-class="badge-item">
<view class="box"><text class="text">消息</text></view>
</ux-badge>
<ux-badge :count="200" custom-class="badge-item">
<view class="box"><text class="text">消息</text></view>
</ux-badge>
</view>
</template>
<style scoped>
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: visible;
}
.badge-item {
margin-right: 20px;
margin-bottom: 15px;
}
.box {
width: 60px;
height: 60px;
background-color: #f7f8fa;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.text {
font-size: 13px;
color: #909399;
}
</style>Preset Types (type)
type switches the preset background: error (default) / primary / success / warning / info.
View source
<template>
<view class="row">
<ux-badge
v-for="(item, index) in typeList"
:key="index"
:type="item.type"
:count="8"
custom-class="badge-item"
>
<view class="box"><text class="text">{{ item.label }}</text></view>
</ux-badge>
</view>
</template>
<script setup lang="uts">
const typeList = [
{ type: 'error', label: 'error' },
{ type: 'primary', label: 'primary' },
{ type: 'success', label: 'success' },
{ type: 'warning', label: 'warning' },
{ type: 'info', label: 'info' }
];
</script>
<style scoped>
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: visible;
}
.badge-item {
margin-right: 20px;
margin-bottom: 15px;
}
.box {
width: 60px;
height: 60px;
background-color: #f7f8fa;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.text {
font-size: 13px;
color: #909399;
}
</style>Dot Mode (is-dot)
is-dot shows only a small dot instead of a number, often paired with is-center for message reminders.
View source
<template>
<view class="row">
<ux-badge :is-dot="true" is-center custom-class="badge-item">
<view class="box"><text class="text">消息</text></view>
</ux-badge>
<ux-badge :is-dot="true" type="primary" is-center custom-class="badge-item">
<view class="box"><text class="text">通知</text></view>
</ux-badge>
<ux-badge :is-dot="true" type="warning" is-center custom-class="badge-item">
<view class="box"><text class="text">提醒</text></view>
</ux-badge>
</view>
</template>
<style scoped>
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: visible;
}
.badge-item {
margin-right: 20px;
margin-bottom: 15px;
}
.box {
width: 60px;
height: 60px;
background-color: #f7f8fa;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.text {
font-size: 13px;
color: #909399;
}
</style>Mini Size (size="mini")
size="mini" renders a smaller badge (scaled to 0.8).
View source
<template>
<view class="row">
<ux-badge :count="5" custom-class="badge-item">
<view class="box"><text class="text">默认</text></view>
</ux-badge>
<ux-badge :count="5" size="mini" custom-class="badge-item">
<view class="box"><text class="text">mini</text></view>
</ux-badge>
</view>
</template>
<style scoped>
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: visible;
}
.badge-item {
margin-right: 20px;
margin-bottom: 15px;
}
.box {
width: 60px;
height: 60px;
background-color: #f7f8fa;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.text {
font-size: 13px;
color: #909399;
}
</style>Overflow Count (overflow-count)
overflow-count sets a custom cap; values above it render as the cap plus +.
View source
<template>
<view class="row">
<ux-badge :count="100" :overflow-count="99" custom-class="badge-item">
<view class="box"><text class="text">99+</text></view>
</ux-badge>
<ux-badge :count="10" :overflow-count="9" custom-class="badge-item">
<view class="box"><text class="text">9+</text></view>
</ux-badge>
<ux-badge :count="1000" :overflow-count="999" custom-class="badge-item">
<view class="box"><text class="text">999+</text></view>
</ux-badge>
</view>
</template>
<style scoped>
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: visible;
}
.badge-item {
margin-right: 20px;
margin-bottom: 15px;
}
.box {
width: 60px;
height: 60px;
background-color: #f7f8fa;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.text {
font-size: 13px;
color: #909399;
}
</style>Show Zero (show-zero)
With count=0 and show-zero=false (default) the badge is hidden; set it to true to show 0.
View source
<template>
<view class="row">
<ux-badge :count="0" :show-zero="false" custom-class="badge-item">
<view class="box"><text class="text">隐藏0</text></view>
</ux-badge>
<ux-badge :count="0" :show-zero="true" custom-class="badge-item">
<view class="box"><text class="text">显示0</text></view>
</ux-badge>
</view>
</template>
<style scoped>
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: visible;
}
.badge-item {
margin-right: 20px;
margin-bottom: 15px;
}
.box {
width: 60px;
height: 60px;
background-color: #f7f8fa;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.text {
font-size: 13px;
color: #909399;
}
</style>Custom Color
bg-color / color / font-size override the badge background, text color, and font size; bg-color takes precedence over type.
View source
<template>
<view class="row">
<ux-badge :count="8" bg-color="#7232dd" color="#ffffff" custom-class="badge-item">
<view class="box"><text class="text">自定义</text></view>
</ux-badge>
<ux-badge :count="16" bg-color="#19be6b" color="#ffffff" custom-class="badge-item">
<view class="box"><text class="text">自定义</text></view>
</ux-badge>
<ux-badge :count="3" bg-color="#ff9900" color="#ffffff" font-size="16" custom-class="badge-item">
<view class="box"><text class="text">自定义</text></view>
</ux-badge>
</view>
</template>
<style scoped>
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: visible;
}
.badge-item {
margin-right: 20px;
margin-bottom: 15px;
}
.box {
width: 60px;
height: 60px;
background-color: #f7f8fa;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.text {
font-size: 13px;
color: #909399;
}
</style>Position Offset (offset)
offset is [top, right] in px, positioning the badge relative to its host.
View source
<template>
<view class="row">
<view class="demo">
<ux-badge :count="5" :offset="[0, 0]">
<view class="box"><text class="text">基准</text></view>
</ux-badge>
<text class="label">[0, 0]</text>
</view>
<view class="demo">
<ux-badge :count="5" :offset="[-5, -5]">
<view class="box"><text class="text">凸出</text></view>
</ux-badge>
<text class="label">[-10, -10]</text>
</view>
<view class="demo">
<ux-badge :count="5" :offset="[8, 15]">
<view class="box"><text class="text">向内</text></view>
</ux-badge>
<text class="label">[15, 30]</text>
</view>
</view>
</template>
<style scoped>
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: visible;
}
.demo {
display: flex;
flex-direction: column;
align-items: center;
margin-right: 25px;
margin-bottom: 15px;
flex-shrink: 0;
overflow: visible;
}
.label {
font-size: 11px;
color: #c8c9cc;
margin-top: 10px;
}
.box {
width: 60px;
height: 60px;
background-color: #f7f8fa;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.text {
font-size: 13px;
color: #909399;
white-space: nowrap;
}
</style>Center Overlap (is-center)
is-center aligns the badge center with the parent's top-right corner, making offset ineffective.
View source
<template>
<view class="row">
<ux-badge :count="5" :offset="[-5, -5]" custom-class="badge-item">
<view class="box"><text class="text">普通</text></view>
</ux-badge>
<ux-badge :count="5" :is-center="true" custom-class="badge-item">
<view class="box"><text class="text">居中</text></view>
</ux-badge>
<ux-badge :is-dot="true" :is-center="true" type="primary" custom-class="badge-item">
<view class="box"><text class="text">圆点</text></view>
</ux-badge>
</view>
</template>
<style scoped>
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: visible;
}
.badge-item {
margin-right: 20px;
margin-bottom: 15px;
}
.box {
width: 60px;
height: 60px;
background-color: #f7f8fa;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.text {
font-size: 13px;
color: #909399;
}
</style>Dual Modes
With the default slot the badge pins itself to the top-right; without content it acts as a standalone badge over a relatively positioned host.
View source
<template>
<view class="dual">
<view class="card">
<text class="mode">包裹模式</text>
<ux-badge :count="3" :offset="[-5, -5]">
<view class="box"><text class="text">消息</text></view>
</ux-badge>
<text class="desc">内容放默认插槽,组件自带定位锚点,角标自动置于右上角,宿主零配置</text>
</view>
<view class="card">
<text class="mode">单用模式</text>
<view class="host">
<view class="box"><text class="text">消息</text></view>
<ux-badge :count="3" :offset="[-5, -5]"></ux-badge>
</view>
<text class="desc">不传内容,作为独立角标叠加到宿主的相对定位右上角</text>
</view>
</view>
</template>
<style scoped>
.dual {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: visible;
}
.card {
display: flex;
flex-direction: column;
align-items: flex-start;
margin-right: 25px;
margin-bottom: 15px;
flex-shrink: 0;
overflow: visible;
}
.mode {
font-size: 12px;
color: #606266;
margin-bottom: 8px;
}
.desc {
font-size: 11px;
color: #c8c9cc;
margin-top: 8px;
}
.box {
width: 60px;
height: 60px;
background-color: #f7f8fa;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.text {
font-size: 13px;
color: #909399;
white-space: nowrap;
}
.host {
/* 单用模式需宿主自行提供定位锚点 */
position: relative;
overflow: visible;
}
</style>Non-Absolute Positioning (absolute=false)
absolute=false disables absolute positioning so the badge flows inline and offset no longer applies.
View source
<template>
<view class="inline-row">
<text>未读消息</text>
<ux-badge :count="12" :absolute="false" custom-class="badge-inline"></ux-badge>
</view>
<view class="inline-row">
<text>新通知</text>
<ux-badge :is-dot="true" :absolute="false" type="success" custom-class="badge-inline"></ux-badge>
</view>
</template>
<style scoped>
.inline-row {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 10px;
}
.badge-inline {
margin-left: 8px;
}
</style>API
Props
| Property | Description | Type | Default | Version |
|---|---|---|---|---|
customStyle | Custom root element style | string | UTSJSONObject | - | - |
customClass | Custom root element style class | string | '' | - |
type | Preset background color: primary / warning / success / error / info | ThemeType | 'error' | - |
size | Badge size: default / mini | BadgeSize | 'default' | - |
isDot | Whether to show a dot instead of a number | boolean | false | - |
count | Value to display; above overflow-count it renders as the cap plus +, and 0 is hidden unless show-zero is set | string | number | null | - |
overflowCount | Capping value; counts above it render as the cap plus + | number | 99 | - |
showZero | Whether to show the badge when the value is 0 | boolean | false | - |
offset | Position offset [number, number] (top, right) | number[] | - | - |
absolute | Whether to use absolute positioning; offset only works when enabled | boolean | true | - |
fontSize | Font size | string | number | DEFAULT_FONT_SIZE | - |
color | Font color | string | '' | - |
bgColor | Badge background color (takes precedence over type) | string | '' | - |
isCenter | Whether the badge center overlaps the parent's top-right corner; when set, offset is ignored | boolean | false | - |
Events
ux-badge has no events.
Slots
| Slot | Description | Version |
|---|---|---|
default | Wrapping mode: host content the badge annotates (when provided, the component supplies its own anchor and pins the badge to the top-right) | - |
content | Custom badge inner content, replacing the default count text | - |
Notes
- Two usages: with the default slot it is "wrapping mode" — the component supplies its own
relative+overflow: visibleanchor and pins the badge to the top-right; without it, it is "standalone/overlay mode" and the host must provideposition: relativeas the anchor. is-centertakes precedence overoffset: when true the badge center overlaps the parent's top-right corner andoffsetis ignored.bg-colortakes precedence overtype, so thetypepreset background is ignored once it is set.is-dot=truekeeps the badge always visible and ignorescount/overflow-count; withcount0 andshow-zero=falsethe badge is hidden entirely.- A
countaboveoverflow-count(default 99) renders as the cap plus+(e.g.99+). - With
absolute=false(and no default slot) the badge is not absolutely positioned,offsetno longer applies, and the badge flows inline with the content. - A badge protruding beyond its host relies on
overflow: visible: the component declares it on both the wrapping layer and the badge node, but in standalone mode a host container that clips will still cut the badge off.