npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rcaferati/vue-awesome-button

v1.2.0

Published

Vue 3D button components with progress states, social sharing, themes, and animated transitions

Readme

Vue <AwesomeButton /> UI Components

@rcaferati/vue-awesome-button provides three related Vue 3 button components:

  • AwesomeButton - animated base button
  • AwesomeButtonProgress - progress flow wrapper on top of AwesomeButton
  • AwesomeButtonSocial - social/share wrapper on top of AwesomeButton

This README is updated for the current 1.0.1 release outputs, including base CSS, bundled theme CSS files, Vue slots, emits, and plugin registration.


Preview

Awesome Button visual preview


Installation

npm install @rcaferati/vue-awesome-button

Quick Start

Import the base stylesheet once, import any theme CSS files you want to use, then render a button with the matching theme prop.

<script setup lang="ts">
import { AwesomeButton } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
import '@rcaferati/vue-awesome-button/themes/theme-blue.css';
</script>

<template>
  <AwesomeButton theme="blue" type="primary">
    Button
  </AwesomeButton>
</template>

Styling With Theme CSS

The Vue package does not use theme mapping objects. Themes are plain CSS files scoped by the theme prop.

Blue theme example

import '@rcaferati/vue-awesome-button/styles.css';
import '@rcaferati/vue-awesome-button/themes/theme-blue.css';
<AwesomeButton theme="blue" type="primary">
  Button
</AwesomeButton>

Multiple themes in the same app

Import each theme CSS file once, then switch themes per button instance.

import '@rcaferati/vue-awesome-button/styles.css';
import '@rcaferati/vue-awesome-button/themes/theme-blue.css';
import '@rcaferati/vue-awesome-button/themes/theme-rickiest.css';
<template>
  <AwesomeButton theme="blue" type="primary">
    Blue
  </AwesomeButton>

  <AwesomeButton theme="rickiest" type="secondary">
    Rickiest
  </AwesomeButton>
</template>

Bundled themes

  • theme-amber.css
  • theme-blue.css
  • theme-bojack.css
  • theme-bruce.css
  • theme-c137.css
  • theme-eric.css
  • theme-flat.css
  • theme-indigo.css
  • theme-red.css
  • theme-rickiest.css

Plugin Registration

Use the plugin if you want global component registration.

import { createApp } from 'vue';
import App from './App.vue';
import { AwesomeButtonPlugin } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
import '@rcaferati/vue-awesome-button/themes/theme-blue.css';

createApp(App).use(AwesomeButtonPlugin).mount('#app');

After registration, AwesomeButton, AwesomeButtonProgress, and AwesomeButtonSocial are available in templates without local imports.


AwesomeButton

Basic button behavior

If href is not provided, AwesomeButton renders button-like behavior and emits press on successful activation.

<script setup lang="ts">
import { AwesomeButton } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
import '@rcaferati/vue-awesome-button/themes/theme-blue.css';

function handleSave() {
  // do something
}
</script>

<template>
  <AwesomeButton theme="blue" type="primary" @press="handleSave">
    Save changes
  </AwesomeButton>
</template>

Anchor mode (href provided)

If href is provided, the component renders anchor-like behavior and lets native navigation happen. Normal Vue attrs are forwarded to the root element.

<script setup lang="ts">
import { AwesomeButton } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
import '@rcaferati/vue-awesome-button/themes/theme-blue.css';
</script>

<template>
  <AwesomeButton
    theme="blue"
    type="link"
    href="https://github.com/rcaferati"
    target="_blank"
    rel="noreferrer noopener"
  >
    Open website
  </AwesomeButton>
</template>

Icons with slots

Use before and after slots to render icons. For icon-only buttons, pass the icon with a named slot and omit default slot text.

<script setup lang="ts">
import { AwesomeButton } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
import '@rcaferati/vue-awesome-button/themes/theme-blue.css';
</script>

<template>
  <div style="display: grid; gap: 12px;">
    <AwesomeButton theme="blue" type="primary" size="medium">
      <template #before>
        <svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16">
          <path d="M12 3l1.9 4.8L19 9.2l-4 3.4 1.3 5.2L12 15l-4.3 2.8L9 12.6 5 9.2l5.1-1.4L12 3z" />
        </svg>
      </template>

      Continue

      <template #after>
        <svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16">
          <path d="M5 12h14" />
          <path d="m13 5 7 7-7 7" />
        </svg>
      </template>
    </AwesomeButton>

    <AwesomeButton theme="blue" type="primary" size="medium" aria-label="Play">
      <template #before>
        <svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16">
          <path d="M8 5v14l11-7z" />
        </svg>
      </template>
    </AwesomeButton>
  </div>
</template>

Sizes and auto width

  • size="small" | "medium" | "large" uses fixed button dimensions.
  • :size="null" uses content-driven auto width.
  • Fixed-size changes and measured auto-width changes animate by default. Use :animate-size="false" to opt out.
  • Switching between fixed size and auto width is intentionally instant in this release.
<script setup lang="ts">
import { AwesomeButton } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
import '@rcaferati/vue-awesome-button/themes/theme-blue.css';
</script>

<template>
  <div style="display: grid; gap: 12px;">
    <AwesomeButton theme="blue" size="small" type="primary">
      Small
    </AwesomeButton>
    <AwesomeButton theme="blue" size="medium" type="primary">
      Medium
    </AwesomeButton>
    <AwesomeButton theme="blue" size="large" type="primary">
      Large
    </AwesomeButton>
    <AwesomeButton theme="blue" :size="null" type="primary">
      Auto width grows with content
    </AwesomeButton>
    <AwesomeButton theme="blue" size="large" type="primary" :animate-size="false">
      Instant fixed-size change
    </AwesomeButton>
  </div>
</template>

Text transition (string labels only)

Use text-transition when the default slot resolves to a plain string and you want label changes to animate.

<script setup lang="ts">
import { ref } from 'vue';
import { AwesomeButton } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';

const expanded = ref(false);
</script>

<template>
  <AwesomeButton
    type="primary"
    :size="null"
    text-transition
    @press="expanded = !expanded"
  >
    {{ expanded ? 'Processing settlement report' : 'Generate report' }}
  </AwesomeButton>
</template>

AwesomeButton Slots, Emits, and Props

Slots

| Slot | Description | | --- | --- | | before | Content rendered before the main label, commonly an icon | | default | Main label/content | | after | Content rendered after the main label, commonly an icon | | extra | Extra wrapper content used by wrappers such as progress |

Emits

| Emit | Payload | Description | | --- | --- | --- | | press | MouseEvent \| KeyboardEvent \| PointerEvent | Successful activation/release | | pressed | MouseEvent \| KeyboardEvent \| PointerEvent | Press-in interaction started | | released | HTMLElement \| null | Release cycle cleared |

Props

| Prop | Type | Default | Description | | --- | --- | --- | --- | | type | string | "primary" | Visual variant key, such as primary, secondary, danger, link, or a social visual variant | | size | "small" \| "medium" \| "large" \| null | "medium" | Size key or null for auto width | | active | boolean | false | Controlled pressed/active visual state | | disabled | boolean | false | Disables interactions | | visible | boolean | true | Toggles visible state class | | placeholder | boolean | false | Renders placeholder/skeleton state | | lockedHover | boolean | false | Locks the visual middle-hover position without changing interactivity | | animateSize | boolean | true | Animates fixed-size and measured auto-width changes | | textTransition | boolean | false | Animates string-only label changes | | between | boolean | false | Uses space-between layout for content | | ripple | boolean | false | Enables ripple effect on successful activation | | moveEvents | boolean | true | Enables pointer move position classes | | href | string \| null | null | Enables anchor-like mode | | as | string \| Component | "button" | Root element/component when href is not set | | theme | ThemeName \| null | null | Applies a bundled theme marker class, such as blue |

Normal Vue attrs such as class, style, aria-*, target, and rel are forwarded to the rendered root element.

<AwesomeButton disabled locked-hover>
  Locked hover
</AwesomeButton>

AwesomeButtonProgress

AwesomeButtonProgress wraps AwesomeButton and manages a guarded progress lifecycle. Its press emit receives a second callback argument:

  • next(true) starts the success flow
  • next(false, 'Failed') starts the error flow with an optional label override

Basic success flow

<script setup lang="ts">
import { AwesomeButtonProgress } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
import '@rcaferati/vue-awesome-button/themes/theme-blue.css';

const sleep = (ms: number) => new Promise((resolve) => window.setTimeout(resolve, ms));

async function handleVerify(
  _event: MouseEvent | KeyboardEvent | PointerEvent,
  next: (endState?: boolean, errorLabel?: string | null) => void
) {
  await sleep(900);
  next(true);
}
</script>

<template>
  <AwesomeButtonProgress
    theme="blue"
    type="primary"
    loading-label="Verifying..."
    result-label="Verified!"
    :release-delay="500"
    @press="handleVerify"
  >
    Verify
  </AwesomeButtonProgress>
</template>

Error flow

<script setup lang="ts">
import { AwesomeButtonProgress } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';

const sleep = (ms: number) => new Promise((resolve) => window.setTimeout(resolve, ms));

async function handlePublish(
  _event: MouseEvent | KeyboardEvent | PointerEvent,
  next: (endState?: boolean, errorLabel?: string | null) => void
) {
  await sleep(900);
  next(false, 'Failed');
}
</script>

<template>
  <AwesomeButtonProgress
    type="danger"
    loading-label="Publishing..."
    result-label="Done!"
    @press="handlePublish"
  >
    Publish
  </AwesomeButtonProgress>
</template>

Text-only progress and custom bar timing

Use :show-progress-bar="false" to keep the loading/result text flow while hiding the dark loading bar. Use progress-loading-time to control how long the progress bar takes to advance during the loading phase.

<script setup lang="ts">
import { AwesomeButtonProgress } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';

const sleep = (ms: number) => new Promise((resolve) => window.setTimeout(resolve, ms));

async function handleSync(
  _event: MouseEvent | KeyboardEvent | PointerEvent,
  next: (endState?: boolean, errorLabel?: string | null) => void
) {
  await sleep(900);
  next(true);
}
</script>

<template>
  <AwesomeButtonProgress
    type="primary"
    loading-label="Syncing..."
    result-label="Synced!"
    :show-progress-bar="false"
    :progress-loading-time="1500"
    @press="handleSync"
  >
    Sync account
  </AwesomeButtonProgress>
</template>

With icon (before slot)

<script setup lang="ts">
import { AwesomeButtonProgress } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
import '@rcaferati/vue-awesome-button/themes/theme-blue.css';

const sleep = (ms: number) => new Promise((resolve) => window.setTimeout(resolve, ms));

async function handleVerify(
  _event: MouseEvent | KeyboardEvent | PointerEvent,
  next: (endState?: boolean, errorLabel?: string | null) => void
) {
  await sleep(900);
  next(true);
}
</script>

<template>
  <AwesomeButtonProgress
    theme="blue"
    type="primary"
    size="medium"
    loading-label="Verifying..."
    result-label="Verified!"
    @press="handleVerify"
  >
    <template #before>
      <svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16">
        <path d="M12 2l8 4v6c0 5-3.4 8.7-8 10-4.6-1.3-8-5-8-10V6l8-4z" />
      </svg>
    </template>

    Verify signature
  </AwesomeButtonProgress>
</template>

AwesomeButtonProgress specific props

AwesomeButtonProgress accepts all AwesomeButton props except public active, and replaces the base press payload with the progress version below.

| Prop | Type | Default | Description | | --- | --- | --- | --- | | loadingLabel | string | "Wait.." | Loading phase label | | resultLabel | string | "Success!" | Success label | | releaseDelay | number | 500 | Delay before reset after progress end | | showProgressBar | boolean | true | Hides the dark loading bar when false, while keeping the progress flow | | progressLoadingTime | number | 6000 | Loading-phase progress bar duration in milliseconds | | @press | (event, next) => void | - | Progress handler. Call next(true) or next(false, label?) |


AwesomeButtonSocial

AwesomeButtonSocial wraps AwesomeButton and builds a share action when no custom press listener is provided.

Behavior summary

On activation, the component behaves like this:

  1. If you listen to @press, your handler is called and the built-in sharer logic is skipped
  2. If href is provided, the forwarded base anchor still navigates normally
  3. If there is no href and no custom sharer override, mobile-capable environments attempt navigator.share(...)
  4. Otherwise, the built-in sharer uses a type-specific web share URL, direct URL, or centered popup where supported

If you want a pure custom action with no native navigation, avoid combining @press with href.

Basic share example (LinkedIn)

<script setup lang="ts">
import { AwesomeButtonSocial } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
import '@rcaferati/vue-awesome-button/themes/theme-blue.css';
</script>

<template>
  <AwesomeButtonSocial
    theme="blue"
    type="linkedin"
    :size="null"
    :sharer="{
      url: 'https://example.com',
      message: 'Check this out'
    }"
  >
    <template #before>
      <svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16">
        <path d="M4 3.5A2.5 2.5 0 1 1 4 8.5a2.5 2.5 0 0 1 0-5zM2 10h4v11H2V10zm7 0h4v1.6c.6-1 1.9-1.9 3.9-1.9 4.2 0 5 2.8 5 6.4V21h-4v-4.4c0-2.1 0-3.8-2.3-3.8-2.3 0-2.6 1.8-2.6 3.7V21H9V10z" />
      </svg>
    </template>

    LinkedIn
  </AwesomeButtonSocial>
</template>

Visual-only social style (GitHub look, link behavior)

github is a visual style in the bundled themes. If you want a GitHub-looking button that opens a profile or repo, use href.

<script setup lang="ts">
import { AwesomeButtonSocial } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
import '@rcaferati/vue-awesome-button/themes/theme-blue.css';
</script>

<template>
  <AwesomeButtonSocial
    theme="blue"
    type="github"
    href="https://github.com/rcaferati"
    target="_blank"
    rel="noreferrer noopener"
  >
    <template #before>
      <svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16">
        <path d="M12 .5a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2c-3.3.7-4-1.4-4-1.4-.6-1.4-1.3-1.8-1.3-1.8-1.1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1.1 1.8 2.8 1.3 3.5 1 .1-.8.4-1.3.8-1.6-2.7-.3-5.5-1.3-5.5-5.9 0-1.3.5-2.4 1.2-3.2-.1-.3-.5-1.5.1-3.2 0 0 1-.3 3.3 1.2a11.5 11.5 0 0 1 6 0c2.3-1.5 3.3-1.2 3.3-1.2.7 1.7.2 2.9.1 3.2.8.8 1.2 1.9 1.2 3.2 0 4.6-2.8 5.6-5.5 5.9.4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6A12 12 0 0 0 12 .5z" />
      </svg>
    </template>

    Open GitHub
  </AwesomeButtonSocial>
</template>

WhatsApp example

<script setup lang="ts">
import { AwesomeButtonSocial } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
</script>

<template>
  <AwesomeButtonSocial
    type="whatsapp"
    :sharer="{
      phone: '5511999999999',
      message: 'Hello from AwesomeButton',
      url: 'https://example.com'
    }"
  >
    WhatsApp
  </AwesomeButtonSocial>
</template>

Instagram-style button (direct URL fallback)

instagram is treated as a direct URL fallback. It does not use a dedicated web popup sharer endpoint.

<script setup lang="ts">
import { AwesomeButtonSocial } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
</script>

<template>
  <AwesomeButtonSocial
    type="instagram"
    :sharer="{
      url: 'https://example.com',
      message: 'Open this link'
    }"
  >
    Instagram
  </AwesomeButtonSocial>
</template>

href mode (bypass sharer logic)

If href is present, the component behaves like an anchor and does not execute the built-in share flow.

<script setup lang="ts">
import { AwesomeButtonSocial } from '@rcaferati/vue-awesome-button';
import '@rcaferati/vue-awesome-button/styles.css';
</script>

<template>
  <AwesomeButtonSocial
    type="github"
    href="https://github.com/rcaferati"
    target="_blank"
    rel="noreferrer noopener"
  >
    Open GitHub
  </AwesomeButtonSocial>
</template>

AwesomeButtonSocial specific props

AwesomeButtonSocial accepts all AwesomeButton props and adds the props below.

| Prop | Type | Default | Description | | --- | --- | --- | --- | | sharer | SharerConfig | {} | Share payload source, with page metadata fallbacks where available | | dimensions | { width: number; height: number } | { width: 640, height: 480 } | Popup window dimensions for share flows | | sharer.url | string | current page URL | URL to share, falling back to window.location.href | | sharer.message | string | page title | Share message/text, falling back to document.title | | sharer.image | string | og:image meta | Image URL used by supported sharers, such as Pinterest | | sharer.phone | string | null | Phone for WhatsApp | | sharer.user | string | null | Username for Messenger direct flow |

Supported share type values

The built-in sharer recognizes:

  • facebook
  • twitter
  • pinterest
  • linkedin
  • reddit
  • whatsapp
  • messenger
  • mail
  • instagram

You can use other type values as visual styles if the CSS includes them. The bundled visual-only social styles include github, gplus, and youtube.


Recommended Patterns

Icon-only buttons

Use a named icon slot and omit default slot text. Add an accessible label through normal Vue attrs.

<AwesomeButton type="primary" aria-label="Play">
  <template #before>
    <svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16">
      <path d="M8 5v14l11-7z" />
    </svg>
  </template>
</AwesomeButton>

Progress buttons

Use the progress @press contract and call next(true) or next(false, label?) when the work completes.

import type { ProgressNext } from '@rcaferati/vue-awesome-button';

async function save(_event: MouseEvent | KeyboardEvent | PointerEvent, next: ProgressNext) {
  try {
    await saveRecord();
    next(true);
  } catch {
    next(false, 'Failed');
  }
}

Social buttons

Use slots for icons. The social component does not require bundled icons to work.


Package Exports

  • @rcaferati/vue-awesome-button
  • @rcaferati/vue-awesome-button/AwesomeButton
  • @rcaferati/vue-awesome-button/AwesomeButtonProgress
  • @rcaferati/vue-awesome-button/AwesomeButtonSocial
  • @rcaferati/vue-awesome-button/plugin
  • @rcaferati/vue-awesome-button/styles.css
  • @rcaferati/vue-awesome-button/themes/theme-amber.css
  • @rcaferati/vue-awesome-button/themes/theme-blue.css
  • @rcaferati/vue-awesome-button/themes/theme-bojack.css
  • @rcaferati/vue-awesome-button/themes/theme-bruce.css
  • @rcaferati/vue-awesome-button/themes/theme-c137.css
  • @rcaferati/vue-awesome-button/themes/theme-eric.css
  • @rcaferati/vue-awesome-button/themes/theme-flat.css
  • @rcaferati/vue-awesome-button/themes/theme-indigo.css
  • @rcaferati/vue-awesome-button/themes/theme-red.css
  • @rcaferati/vue-awesome-button/themes/theme-rickiest.css

Author

Rafael Caferati
Website: https://caferati.dev
LinkedIn: https://linkedin.com/in/rcaferati
Instagram: https://instagram.com/rcaferati


License

MIT