Button
17:06Description
A secondary wrapper based on the uni-app button, with more theme colors and optional click ripple effects.
Compatibility
| Platform | Support |
|---|---|
| App | ✅ Supported |
| H5 | ✅ Supported |
| WeChat Mini Program | ✅ Supported |
Examples
Basic Usage
Default theme by default; click triggers the click event.
View source
<template>
<view class="btn-wrap">
<!-- 纯文字用 text 属性传入,组件自动着色(App 端也可正常显示) -->
<ux-button text="普通按钮" @click="onClick" />
</view>
</template>
<script setup lang="uts">
function onClick(): void {
uni.showToast({ title: '点击了按钮', icon: 'none' });
}
</script>
<style scoped>
/* 按钮默认在块级容器中全宽居中,如需收缩靠左排列用 flex 容器包裹 */
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
</style>Theme Types (type)
Supports default / primary / success / error / warning / info themes.
View source
<template>
<view class="btn-grid">
<ux-button v-for="(item, index) in typeList" :key="index" :type="item.type" :text="item.label" custom-class="btn-grid-item" @click="onClick" />
</view>
</template>
<script setup lang="uts">
const typeList = [
{ type: 'default', label: 'default' },
{ type: 'primary', label: 'primary' },
{ type: 'success', label: 'success' },
{ type: 'error', label: 'error' },
{ type: 'warning', label: 'warning' },
{ type: 'info', label: 'info' }
];
function onClick(): void {
uni.showToast({ title: '点击了按钮', icon: 'none' });
}
</script>
<style scoped>
.btn-grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.btn-grid-item {
width: 30%;
margin-bottom: 12px;
}
</style>Plain (plain)
When plain=true, the background is transparent, showing only the border and text.
View source
<template>
<view class="btn-grid">
<ux-button v-for="(item, index) in typeList" :key="index" :type="item.type" :text="item.label" plain custom-class="btn-grid-item" @click="onClick" />
</view>
</template>
<script setup lang="uts">
const typeList = [
{ type: 'default', label: 'default' },
{ type: 'primary', label: 'primary' },
{ type: 'success', label: 'success' },
{ type: 'error', label: 'error' },
{ type: 'warning', label: 'warning' },
{ type: 'info', label: 'info' }
];
function onClick(): void {
uni.showToast({ title: '点击了按钮', icon: 'none' });
}
</script>
<style scoped>
.btn-grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.btn-grid-item {
width: 30%;
margin-bottom: 12px;
}
</style>Sizes (size)
Supports large / default / small sizes.
View source
<template>
<view class="btn-stack">
<ux-button v-for="(item, index) in sizeList" :key="index" :size="item.size" type="primary" :text="item.label" custom-class="btn-stack-item" @click="onClick" />
</view>
</template>
<script setup lang="uts">
const sizeList = [
{ size: 'large', label: 'large' },
{ size: 'default', label: 'default' },
{ size: 'small', label: 'small' }
];
function onClick(): void {
uni.showToast({ title: '点击了按钮', icon: 'none' });
}
</script>
<style scoped>
.btn-stack {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.btn-stack-item {
margin-bottom: 12px;
}
</style>Shape (shape)
shape="square" for a small radius (4px, default), shape="round" for a capsule, shape="circle" for a perfect circle (requires equal width and height). Pass :border-radius="0" for a true sharp corner.
View source
<template>
<view class="btn-wrap">
<ux-button shape="square" type="primary" text="小圆角" custom-class="btn-item" @click="onClick" />
<ux-button shape="round" type="primary" text="胶囊" custom-class="btn-item" @click="onClick" />
<!-- circle 为正圆(需宽高相等),故只放图标;带文字会撑成椭圆 -->
<ux-button shape="circle" type="primary" icon="star" custom-class="btn-item" @click="onClick" />
</view>
</template>
<script setup lang="uts">
function onClick(): void {
uni.showToast({ title: '点击了按钮', icon: 'none' });
}
</script>
<style scoped>
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
.btn-item {
margin-right: 12px;
margin-bottom: 12px;
}
</style>Custom Corner (border-radius)
border-radius takes precedence over the shape presets, letting you set any corner value (in px); pass 0 for a true sharp corner.
View source
<template>
<view class="btn-wrap">
<!-- border-radius(单位px)优先级高于 shape 预设,可定制任意圆角;传 0 即为真直角 -->
<ux-button shape="square" :border-radius="0" type="primary" text="直角 0" custom-class="btn-item" @click="onClick" />
<ux-button :border-radius="4" type="primary" text="圆角 4" custom-class="btn-item" @click="onClick" />
<ux-button :border-radius="12" type="error" plain text="圆角 12" custom-class="btn-item" @click="onClick" />
<ux-button :border-radius="24" type="success" text="圆角 24" custom-class="btn-item" @click="onClick" />
</view>
</template>
<script setup lang="uts">
function onClick(): void {
uni.showToast({ title: '点击了按钮', icon: 'none' });
}
</script>
<style scoped>
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
.btn-item {
margin-right: 12px;
margin-bottom: 12px;
}
</style>Ripple (ripple)
When ripple=true, enables click ripple effect; ripple-bg-color customizes the ripple color.
View source
<template>
<view class="btn-wrap">
<ux-button ripple type="primary" text="水波纹" custom-class="btn-item" @click="onClick" />
<ux-button ripple ripple-bg-color="rgba(255, 255, 255, 0.3)" type="error" text="水波纹" custom-class="btn-item" @click="onClick" />
</view>
</template>
<script setup lang="uts">
function onClick(): void {
uni.showToast({ title: '点击了按钮', icon: 'none' });
}
</script>
<style scoped>
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
.btn-item {
margin-right: 12px;
margin-bottom: 12px;
}
</style>Ripple is not supported on App
The App-side UCSS has no transform/transition animations, so enabling ripple falls back to the dark pressed-state feedback; H5 / WeChat Mini Program work as expected.
Hairline (hair-line)
When hair-line=false, the hairline border is disabled and a bold border is used.
View source
<template>
<view class="btn-wrap">
<ux-button type="default" text="细边框" custom-class="btn-item" @click="onClick" />
<ux-button :hair-line="false" type="default" text="粗边框" custom-class="btn-item" @click="onClick" />
</view>
</template>
<script setup lang="uts">
function onClick(): void {
uni.showToast({ title: '点击了按钮', icon: 'none' });
}
</script>
<style scoped>
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
.btn-item {
margin-right: 12px;
margin-bottom: 12px;
}
</style>Loading (loading)
When loading=true, shows a loading state and the button is not clickable.
View source
<template>
<view class="btn-wrap">
<ux-button loading type="primary" text="默认文案" loading-text="加载中" custom-class="btn-item" />
<ux-button loading type="success" text="默认文案" loading-text="加载中" custom-class="btn-item" />
</view>
<!-- 加载图标大小 loading-size(单位px,默认按按钮尺寸自动匹配) -->
<view class="btn-wrap">
<ux-button loading type="warning" text="默认文案" loading-text="加载中" loading-size="20" custom-class="btn-item" />
</view>
</template>
<style scoped>
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
.btn-item {
margin-right: 12px;
margin-bottom: 12px;
}
</style>Disabled (disabled)
When disabled=true, the button is grayed out and not clickable; solid colored types (primary/success/error/warning) hide the border, while default/info/hollow keep the hairline border.
View source
<template>
<view class="btn-wrap">
<ux-button disabled type="primary" text="禁用按钮" custom-class="btn-item" />
<ux-button disabled plain type="primary" text="禁用镂空" custom-class="btn-item" />
</view>
<!-- 彩色实心(primary/success/error/warning)禁用时隐藏边框;default/info/镂空保留细边框 -->
<view class="btn-wrap">
<ux-button disabled type="default" text="禁用按钮" custom-class="btn-item" />
<ux-button disabled type="info" text="禁用按钮" custom-class="btn-item" />
<ux-button disabled plain type="success" text="禁用镂空" custom-class="btn-item" />
</view>
</template>
<style scoped>
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
.btn-item {
margin-right: 12px;
margin-bottom: 12px;
}
</style>Icon (icon)
icon specifies the icon name; icon-size controls the size; icon-color controls the color (defaults to the text color).
View source
<template>
<view class="btn-wrap">
<ux-button type="primary" icon="star" text="图标按钮" custom-class="btn-item" @click="onClick" />
<ux-button type="error" plain icon="heart" text="图标按钮" custom-class="btn-item" @click="onClick" />
<ux-button type="default" icon="account" icon-color="#2979ff" text="自定义图标色" custom-class="btn-item" @click="onClick" />
</view>
<!-- 仅图标:不传插槽内容则只显示图标,可配合 shape 组成各形态 -->
<view class="btn-wrap btn-icon-row">
<ux-button shape="round" icon="star" type="primary" custom-class="btn-item" @click="onClick" />
<ux-button shape="round" plain icon="heart" type="error" custom-class="btn-item" @click="onClick" />
<ux-button icon="search" type="success" custom-class="btn-item" @click="onClick" />
<ux-button plain icon="close" type="default" custom-class="btn-item" @click="onClick" />
</view>
<!-- 图标大小 icon-size 与垂直偏移 icon-top(单位px,正数向上) -->
<view class="btn-wrap btn-icon-row">
<ux-button type="primary" icon="star" icon-size="20" text="大号图标" custom-class="btn-item" @click="onClick" />
<ux-button type="primary" icon="star" icon-size="26" :icon-top="2" text="大号图标" custom-class="btn-item" @click="onClick" />
</view>
</template>
<script setup lang="uts">
function onClick(): void {
uni.showToast({ title: '点击了按钮', icon: 'none' });
}
</script>
<style scoped>
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
.btn-item {
margin-right: 12px;
margin-bottom: 12px;
}
.btn-icon-row {
margin-top: 8px;
}
</style>Custom Content (slot)
Plain text via text or default slot (auto-colored); rich custom content via content slot, set color on inner text manually (App does not inherit styles).
View source
<template>
<view class="btn-wrap">
<!-- text 属性:纯文字,组件自动着色 -->
<ux-button type="primary" text="text 属性" custom-class="btn-item" @click="onClick" />
<!-- 特色示例:content 插槽富拼装(保留 icon/loading)—— 促销售价"大号加粗价格 + 白底省 ¥100 徽标",
展示纯文字传达不了的混排能力;页面自定义 class 设色 -->
<ux-button type="error" custom-class="btn-item" @click="onClick">
<template #content>
<text class="slot-price">¥299</text>
<text class="slot-badge">省 ¥100</text>
</template>
</ux-button>
</view>
</template>
<style scoped>
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
.btn-item {
margin-right: 12px;
margin-bottom: 12px;
}
/* 特色插槽:促销售价——大号加粗白字价格 */
.slot-price {
color: #ffffff;
font-size: 20px;
font-weight: bold;
}
/* 特色插槽:促销徽标——白底半透明胶囊 + 深红字 */
.slot-badge {
margin-left: 8px;
padding: 0 8px;
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.92);
color: #ee4d38;
font-size: 12px;
line-height: 20px;
}
</style>Full Width (block)
When block=true, the button fills the entire row width.
View source
<template>
<view class="btn-stack">
<ux-button block type="primary" icon="star" text="占满一行的按钮" custom-class="btn-stack-item" @click="onClick" />
<ux-button block type="success" plain text="占满一行的按钮" custom-class="btn-stack-item" @click="onClick" />
</view>
</template>
<script setup lang="uts">
function onClick(): void {
uni.showToast({ title: '点击了按钮', icon: 'none' });
}
</script>
<style scoped>
.btn-stack {
display: flex;
flex-direction: column;
}
.btn-stack-item {
margin-bottom: 12px;
}
</style>Throttle throttle-time
throttle-time sets the click throttle interval in ms; taps within the interval fire only once.
View source
<template>
<view class="btn-wrap">
<!-- throttle-time=毫秒:不到该间隔的连击只生效一次,右侧按钮在快速连点时会明显丢次数 -->
<ux-button type="primary" text="无节流" custom-class="btn-item" @click="onNormalTap" />
<ux-button type="error" throttle-time="1000" text="节流 1s" custom-class="btn-item" @click="onTap" />
</view>
</template>
<script setup lang="uts">
const normalCount = ref(0);
const throttledCount = ref(0);
function onNormalTap(): void {
normalCount.value++;
uni.showToast({ title: `未节流:${normalCount.value} 次`, icon: 'none' });
}
function onTap(): void {
throttledCount.value++;
uni.showToast({ title: `节流 1s:${throttledCount.value} 次`, icon: 'none' });
}
</script>
<style scoped>
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
.btn-item {
margin-right: 12px;
margin-bottom: 12px;
}
</style>Custom Style (custom-style)
Override the button style via custom-style. In fully-custom scenarios, press feedback (hover/pressing) is also handed over to the custom style; the component does not interfere.
View source
<template>
<view class="btn-wrap">
<!-- 完全自定义场景(黑底白字)组件无法自动推断文字色,用时须在插槽内层显式设 color -->
<ux-button type="default" :custom-style="customStyle" custom-class="btn-item" @click="onClick">
<text :style="slotTextStyle">自定义样式</text>
</ux-button>
</view>
</template>
<script setup lang="uts">
import { createStyle } from '@/uni_modules/uview-pro-x';
const customStyle = computed((): UTSJSONObject => {
const style = createStyle();
style['backgroundColor'] = '#000000';
style['color'] = '#ffffff';
return style;
});
const slotTextStyle = computed((): UTSJSONObject => {
const style = createStyle();
style['color'] = '#ffffff';
return style;
});
function onClick(): void {
uni.showToast({ title: '点击了按钮', icon: 'none' });
}
</script>
<style scoped>
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
</style>API
Props
| Property | Description | Type | Default | Version |
|---|---|---|---|---|
customStyle | Custom root element style | string | UTSJSONObject | - | - |
customClass | Custom root element style class | string | '' | - |
text | Button text. Use for plain text via the text prop or the default slot; the component wraps it in a colored text (text color handled explicitly on App). For rich content (icon + text, custom styles) use the content slot and control the inner text color yourself | string | '' | - |
icon | Icon name (see the ux-icon set); hidden automatically when loading | string | '' | - |
iconSize | Icon size in px; auto-matched to button size when unset | string | number | '' | - |
iconColor | Icon color; defaults to the button text color when unset | string | '' | - |
iconTop | Icon vertical offset in px (positive moves up) | number | 0 | - |
block | Whether the button fills the entire row | boolean | false | - |
hairLine | Whether to use a hairline border | boolean | true | - |
type | Preset style: default / primary / success / error / warning / info | ButtonType | 'default' | - |
size | Button size: large / default / small | ButtonSize | 'default' | - |
shape | Button shape: square – small radius 4px (default), round – capsule, circle – perfect circle; pass border-radius=0 for a true sharp corner | ButtonShape | 'square' | - |
borderRadius | Custom corner radius in px; takes precedence over the shape presets. Default '' means unset (pass 0 for an explicit sharp corner) | string | number | '' | - |
plain | Whether the button is plain (transparent background) | boolean | false | - |
disabled | Whether the button is disabled | boolean | false | - |
loading | Whether the button is in the loading state | boolean | false | - |
loadingText | Text shown while loading; falls back to the button text when unset | string | '' | - |
loadingSize | Loading icon size in px; auto-matched to button size when unset | string | number | '' | - |
scope | Alipay Mini Program: effective when open-type is getAuthorize | ButtonScope | '' | - |
openType | Open capability; see the uni-app button open-capability docs | ButtonOpenType | '' | - |
formType | Used inside <form>; click triggers the form's submit / reset | ButtonFormType | '' | - |
appParameter | Params passed to the App when open-type=launchApp | string | '' | - |
hoverStopPropagation | Whether to stop ancestors from showing the pressed state (WeChat Mini Program only) | boolean | false | - |
lang | Language for returned user info: zh_CN / zh_TW / en (WeChat Mini Program only) | string | 'en' | - |
sessionFrom | Session source; effective when open-type=contact (WeChat Mini Program only) | string | '' | - |
sendMessageTitle | In-session message card title; effective when open-type=contact | string | '' | - |
sendMessagePath | In-session message card jump path; effective when open-type=contact | string | '' | - |
sendMessageImg | In-session message card image; effective when open-type=contact | string | '' | - |
showMessageCard | Whether to show the in-session message card; effective when open-type=contact | boolean | false | - |
rippleBgColor | Ripple background color | string | '' | - |
ripple | Whether to enable the ripple click effect | boolean | false | - |
hoverClass | Class applied while pressed | string | '' | - |
dataName | Extra param passed via the Mini Program data-xxx attribute; read from target.dataset.name | string | '' | - |
throttleTime | Throttle: fire only once within a given interval | string | number | 0 | - |
hoverStartTime | Delay before the pressed state appears (ms) | string | number | 20 | - |
hoverStayTime | How long the pressed state is kept after release (ms) | string | number | 150 | - |
Events
| Event | Description | Params | Version |
|---|---|---|---|
click | Button click | event: UniEvent | - |
getuserinfo | User-info callback; detail matches uni.getUserInfo | event: UniEvent | - |
contact | Customer-service message callback | event: UniEvent | - |
getphonenumber | Effective when open-type=getPhoneNumber | event: UniEvent | - |
error | Called when an open capability errors | event: UniEvent | - |
launchapp | Called when the App opens successfully | event: UniEvent | - |
opensetting | Called after the authorization settings page is closed | event: UniEvent | - |
chooseavatar | Avatar selection callback | event: UniEvent | - |
agreeprivacyauthorization | Called when the user taps to allow authorization | event: UniEvent | - |
Slots
| Slot | Description | Version |
|---|---|---|
default | Plain button text; the component wraps it in a colored text and applies the color (App/H5/Mini Program alike). For plain text use the default slot or the text prop | - |
content | Fully custom text area (icon/view/rich styles mixed); rendered as-is, keeping icon and loading. Set color on the inner text yourself (App does not inherit styles) | - |
Notes
- Prefer the
textprop for plain text — the component colors it automatically bytype, so no manual text color is needed; writing the default slot also works, as the component wraps it in a coloredtext. - Use the
contentslot for rich content: App does not inherit styles, so the inner text must setcolorexplicitly. - To customize the root style (spacing, width/height, etc.) use
custom-classrather than the page's nativeclass;ux-buttondeclaresexternalClasses: ['custom-class'], so the mechanism still passes the page class into the component under the Mini Program style-isolation strategy 2.0. border-radiustakes precedence over theshapepresets and accepts any corner value; pass0for a true sharp corner (sharp corners are not ashapeoption).shape="circle"is a perfect circle requiring equal width and height — text stretches it into an ellipse; it degrades toroundautomatically when combined withblock.- Clicks in the
disabled/loadingstates are intercepted by the component's internal guard and do not emitclick; solid colored types (primary/success/error/warning) hide the border when disabled. - When
loading,iconis hidden automatically, keeping only the loading icon and text; the App-side native loading icon is fixed black, so the component usesux-loadingplus text instead. - The ripple
rippleis only supported on H5 / WeChat Mini Program; on App it falls back to the dark pressed-state feedback. - Attributes such as
open-type(open capability) /form-type(form) only take effect on WeChat Mini Program and are ignored on App / H5. throttle-timeis the click throttle interval (ms); consecutive clicks within the interval fire only once.