Skip to content

Button ​

17:06

Description ​

A secondary wrapper based on the uni-app button, with more theme colors and optional click ripple effects.

Compatibility ​

PlatformSupport
App✅ Supported
H5✅ Supported
WeChat Mini Program✅ Supported

Examples ​

Basic Usage ​

Default theme by default; click triggers the click event.

View source
vue
<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
vue
<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
vue
<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
vue
<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
vue
<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
vue
<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
vue
<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
vue
<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
vue
<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
vue
<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
vue
<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
vue
<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
vue
<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
vue
<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
vue
<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 ​

PropertyDescriptionTypeDefaultVersion
customStyleCustom root element stylestring | UTSJSONObject--
customClassCustom root element style classstring''-
textButton 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 yourselfstring''-
iconIcon name (see the ux-icon set); hidden automatically when loadingstring''-
iconSizeIcon size in px; auto-matched to button size when unsetstring | number''-
iconColorIcon color; defaults to the button text color when unsetstring''-
iconTopIcon vertical offset in px (positive moves up)number0-
blockWhether the button fills the entire rowbooleanfalse-
hairLineWhether to use a hairline borderbooleantrue-
typePreset style: default / primary / success / error / warning / infoButtonType'default'-
sizeButton size: large / default / smallButtonSize'default'-
shapeButton shape: square – small radius 4px (default), round – capsule, circle – perfect circle; pass border-radius=0 for a true sharp cornerButtonShape'square'-
borderRadiusCustom corner radius in px; takes precedence over the shape presets. Default '' means unset (pass 0 for an explicit sharp corner)string | number''-
plainWhether the button is plain (transparent background)booleanfalse-
disabledWhether the button is disabledbooleanfalse-
loadingWhether the button is in the loading statebooleanfalse-
loadingTextText shown while loading; falls back to the button text when unsetstring''-
loadingSizeLoading icon size in px; auto-matched to button size when unsetstring | number''-
scopeAlipay Mini Program: effective when open-type is getAuthorizeButtonScope''-
openTypeOpen capability; see the uni-app button open-capability docsButtonOpenType''-
formTypeUsed inside <form>; click triggers the form's submit / resetButtonFormType''-
appParameterParams passed to the App when open-type=launchAppstring''-
hoverStopPropagationWhether to stop ancestors from showing the pressed state (WeChat Mini Program only)booleanfalse-
langLanguage for returned user info: zh_CN / zh_TW / en (WeChat Mini Program only)string'en'-
sessionFromSession source; effective when open-type=contact (WeChat Mini Program only)string''-
sendMessageTitleIn-session message card title; effective when open-type=contactstring''-
sendMessagePathIn-session message card jump path; effective when open-type=contactstring''-
sendMessageImgIn-session message card image; effective when open-type=contactstring''-
showMessageCardWhether to show the in-session message card; effective when open-type=contactbooleanfalse-
rippleBgColorRipple background colorstring''-
rippleWhether to enable the ripple click effectbooleanfalse-
hoverClassClass applied while pressedstring''-
dataNameExtra param passed via the Mini Program data-xxx attribute; read from target.dataset.namestring''-
throttleTimeThrottle: fire only once within a given intervalstring | number0-
hoverStartTimeDelay before the pressed state appears (ms)string | number20-
hoverStayTimeHow long the pressed state is kept after release (ms)string | number150-

Events ​

EventDescriptionParamsVersion
clickButton clickevent: UniEvent-
getuserinfoUser-info callback; detail matches uni.getUserInfoevent: UniEvent-
contactCustomer-service message callbackevent: UniEvent-
getphonenumberEffective when open-type=getPhoneNumberevent: UniEvent-
errorCalled when an open capability errorsevent: UniEvent-
launchappCalled when the App opens successfullyevent: UniEvent-
opensettingCalled after the authorization settings page is closedevent: UniEvent-
chooseavatarAvatar selection callbackevent: UniEvent-
agreeprivacyauthorizationCalled when the user taps to allow authorizationevent: UniEvent-

Slots ​

SlotDescriptionVersion
defaultPlain 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-
contentFully 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 ​

  1. Prefer the text prop for plain text — the component colors it automatically by type, so no manual text color is needed; writing the default slot also works, as the component wraps it in a colored text.
  2. Use the content slot for rich content: App does not inherit styles, so the inner text must set color explicitly.
  3. To customize the root style (spacing, width/height, etc.) use custom-class rather than the page's native class; ux-button declares externalClasses: ['custom-class'], so the mechanism still passes the page class into the component under the Mini Program style-isolation strategy 2.0.
  4. border-radius takes precedence over the shape presets and accepts any corner value; pass 0 for a true sharp corner (sharp corners are not a shape option).
  5. shape="circle" is a perfect circle requiring equal width and height — text stretches it into an ellipse; it degrades to round automatically when combined with block.
  6. Clicks in the disabled / loading states are intercepted by the component's internal guard and do not emit click; solid colored types (primary/success/error/warning) hide the border when disabled.
  7. When loading, icon is hidden automatically, keeping only the loading icon and text; the App-side native loading icon is fixed black, so the component uses ux-loading plus text instead.
  8. The ripple ripple is only supported on H5 / WeChat Mini Program; on App it falls back to the dark pressed-state feedback.
  9. Attributes such as open-type (open capability) / form-type (form) only take effect on WeChat Mini Program and are ignored on App / H5.
  10. throttle-time is the click throttle interval (ms); consecutive clicks within the interval fire only once.