Skip to content
Welcome to vote for your favorite component! You can also tell me anything you want to say! (*´∀`)~♥

Agile Button button

An extremely agile button ◝( •ω• )◟

Inspired by the Doro meme collaboration from Stellar Blade — the first time I saw it, I couldn't stop laughing. (´,,•ω•,,)

Usage Examples

Basic Usage

When disabled, triggering the button makes it dodge at ultra-high speed. ─=≡Σ((( つ•̀ω•́)つ

View example source code
vue
<template>
  <div class="w-full flex flex-col gap-4 border border-gray-200 rounded-xl p-6">
    <div class="flex flex-col gap-4 border rounded">
      <base-checkbox
        v-model="disabled"
        :label="t('disableButton')"
        class="p-4"
      />
    </div>

    <div class="flex justify-center">
      <btn-agile
        :label="t('clickMe')"
        :disabled="disabled"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import BaseCheckbox from '../../base-checkbox.vue'
import BtnAgile from '../btn-agile.vue'

const { t } = useI18n()

const disabled = ref(true)
</script>

Form Example

Can't click it until you fill out the form! (╯•̀ὤ•́)╯

View example source code
vue
<template>
  <div class="relative w-full flex justify-center border border-gray-200 rounded-xl p-6 py-24">
    <div class="max-w-[20rem] flex flex-col gap-4">
      <base-input
        v-model="form.username"
        :label="t('帳號 *')"
        class="w-full"
      />

      <base-input
        v-model="form.password"
        type="password"
        :label="t('密碼 *')"
        class="w-full"
      />

      <div class="mt-3 flex justify-center">
        <btn-agile
          :label="t('登入')"
          :disabled
          z-index="30"
          @click="handleSubmit"
        />
      </div>
    </div>

    <transition name="opacity">
      <div
        v-if="isSubmitted"
        class="absolute inset-0 z-[40] flex flex-col items-center justify-center gap-6 rounded-xl bg-slate-600 bg-opacity-90 text-white"
        @click="reset"
      >
        <span class="text-xl tracking-wide">
          {{ t('表單已送出!(*´∀`)~♥') }}
        </span>

        <span class="cursor-pointer text-xs">
          {{ t('點一下再來一次') }}
        </span>
      </div>
    </transition>
  </div>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import BaseInput from '../../base-input.vue'
import BtnAgile from '../btn-agile.vue'

const { t } = useI18n()

const form = ref({
  username: '',
  password: '',
})
const disabled = computed(() => {
  return form.value.username === '' || form.value.password === ''
})

const isSubmitted = ref(false)
function handleSubmit() {
  if (disabled.value) {
    return
  }
  isSubmitted.value = true
}

function reset() {
  isSubmitted.value = false

  form.value = {
    username: '',
    password: '',
  }
}
</script>

<style lang="sass" scoped>
.rubbing
  padding: 0.75rem
  color: #ff7530
  opacity: 0.8
  border: 1px dashed #ff7530
  border-radius: 0.2rem
  white-space: nowrap
  text-align: center

.opacity-enter-active, .opacity-leave-active
  transition-duration: 0.4s
.opacity-enter-from, .opacity-leave-to
  opacity: 0 !important
</style>

How It Works

This time we use the trendy Motion library to implement the button animation. ( •̀ ω •́ )✧

Motion leverages hardware acceleration whenever possible, and the Vue version deeply integrates with the reactivity system, delivering excellent performance. It also comes with many useful built-in components.

Highly recommended reading: The Web Animation Performance Tier List

It provides a detailed introduction to the performance characteristics of various animation techniques and Web animation knowledge — quite interesting.

Source Code

API

Props

interface Props {
  /** 按鈕內文字 */
  label?: string;
  /** 是否停用 */
  disabled?: boolean;
  /** 同 CSS z-index */
  zIndex?: number | string;
  /** 同 html tabindex */
  tabindex?: number | string;
}

Emits

const emit = defineEmits<{
  (e: 'click'): void;
}>()

Methods

defineExpose({})

Slots

defineSlots<{
  /** 按鈕 */
  default?: () => unknown;
}>()

v0.60.0