ButtonFx
This library is a work-in-progress. We are releasing it early to gather feedback, but it is not ready for production.
An enhanced button component with customizable animation effects that trigger on hover, click, or mount. ButtonFx extends the base Button component with a rich set of visual effects to create engaging, interactive UI elements.
Opt-in Component
ButtonFx adds a few hundred lines of CSS for animation effects. It's ideal for marketing sites, landing pages, or when visual polish is a priority.
Live Preview
Hover Effects
These effects trigger on hover
Click Effects
These effects trigger on click/active state
Background Effects
Effects that animate the button background
Motion Effects
Dynamic movement effects
Bordered Buttons
Effects work with bordered button styles
Composite Effect
Special multi-stage animation
Speed Variations
Control animation speed with the fxSpeed prop
Easing Functions
Different easing functions create different animation feels
fx-speed="xl" to make easing differences more visible. For production, prefer "sm" or "md" speeds. Disabling Effects
These buttons have fx="bounce" but :fx-disabled="true" prevents the animation from playing while keeping the buttons clickable
View Vue Code
<template>
<section>
<!-- Basic Effects -->
<div class="mbe4">
<h2>Hover Effects</h2>
<p class="mbe2">These effects trigger on hover</p>
</div>
<div class="stacked-mobile mbe6">
<VueButtonFx
fx="bounce"
fx-ease="spring-md"
title="Bounce"
variant="primary"
shape="rounded"
>
Bounce
</VueButtonFx>
<VueButtonFx
fx="pulse"
fx-ease="spring-md"
title="Pulse"
variant="success"
shape="rounded"
>
Pulse
</VueButtonFx>
<VueButtonFx
fx="jelly"
fx-ease="spring-lg"
fx-speed="lg"
title="Jelly button"
variant="warning"
shape="rounded"
>
Jelly
</VueButtonFx>
<VueButtonFx
fx="grow"
fx-ease="spring-md"
title="Grow button"
variant="primary"
shape="rounded"
>
Grow
</VueButtonFx>
<VueButtonFx
fx="shrink"
fx-ease="spring-md"
title="Shrink button"
variant="secondary"
shape="rounded"
>
Shrink
</VueButtonFx>
</div>
<!-- Click Effects -->
<div class="mbe4">
<h2>Click Effects</h2>
<p class="mbe2">These effects trigger on click/active state</p>
</div>
<div class="stacked-mobile mbe6">
<VueButtonFx
fx="press-pop"
fx-ease="spring-sm"
title="Press Pop"
variant="primary"
shape="rounded"
>
Press Pop
</VueButtonFx>
<VueButtonFx
fx="press-pop"
variant="monochrome"
title="Send the email"
shape="rounded-square"
size="lg"
>
<VueIcon no-fill>
<Mail />
</VueIcon>
<VueVisuallyHidden>Send the email</VueVisuallyHidden>
</VueButtonFx>
<VueButtonFx
fx="press-shadow"
variant="warning"
title="Press Shadow"
shape="rounded"
>
Press Shadow
</VueButtonFx>
<VueButtonFx
fx="press-shadow"
variant="success"
title="Press Shadow"
shape="rounded"
>
Press Shadow
</VueButtonFx>
<VueButtonFx
fx="press-shadow"
variant="primary"
title="Shopping cart button"
shape="rounded-square"
size="lg"
>
<VueIcon no-fill>
<ShoppingCart />
</VueIcon>
<VueVisuallyHidden>Proceed to your cart.</VueVisuallyHidden>
</VueButtonFx>
<VueButtonFx
fx="press-shadow"
variant="danger"
title="Dangerous action button"
shape="rounded-square"
size="lg"
>
<VueIcon no-fill>
<Bomb />
</VueIcon>
<VueVisuallyHidden>Do the dangerous thing</VueVisuallyHidden>
</VueButtonFx>
</div>
<!-- Background Effects -->
<div class="mbe4">
<h2>Background Effects</h2>
<p class="mbe2">Effects that animate the button background</p>
</div>
<div class="stacked-mobile mbe6">
<VueButtonFx
fx="bg-slide"
fx-speed="md"
fx-ease="ease-out"
title="BG Slide"
variant="primary"
shape="rounded"
>
BG Slide
</VueButtonFx>
<VueButtonFx
fx="side-slide"
fx-speed="md"
fx-ease="ease-out"
variant="success"
shape="rounded"
>
Side Slide
</VueButtonFx>
</div>
<!-- Motion Effects -->
<div class="mbe4">
<h2>Motion Effects</h2>
<p class="mbe2">Dynamic movement effects</p>
</div>
<div class="stacked-mobile mbe6">
<VueButtonFx
fx="wobble"
fx-ease="spring-md"
title="Wobble"
variant="warning"
shape="rounded"
>
Wobble
</VueButtonFx>
<VueButtonFx
fx="shake"
fx-speed="sm"
title="Shake"
variant="danger"
shape="rounded"
>
Shake
</VueButtonFx>
<VueButtonFx
fx="push"
fx-ease="spring-sm"
title="Push"
variant="primary"
shape="rounded"
>
Push
</VueButtonFx>
</div>
<!-- Bordered Buttons -->
<div class="mbe4">
<h2>Bordered Buttons</h2>
<p class="mbe2">Effects work with bordered button styles</p>
</div>
<div class="stacked-mobile mbe6">
<VueButtonFx
fx="jelly"
fx-ease="spring-lg"
fx-speed="lg"
title="Primary Bordered"
variant="primary"
:bordered="true"
shape="rounded"
>
Primary
</VueButtonFx>
<VueButtonFx
fx="jelly"
fx-speed="lg"
fx-ease="spring-lg"
title="Success Bordered"
variant="success"
:bordered="true"
shape="capsule"
>
Capsule
</VueButtonFx>
<VueButtonFx
fx="jelly"
fx-ease="spring-lg"
fx-speed="lg"
title="Monochrome Bordered"
variant="monochrome"
:bordered="true"
shape="rounded-square"
>
<VueIcon no-fill>
<Trash2 />
</VueIcon>
<VueVisuallyHidden>Toss it in the trash</VueVisuallyHidden>
</VueButtonFx>
<VueButtonFx
fx="jelly"
fx-speed="lg"
fx-ease="spring-lg"
title="Danger Bordered"
variant="danger"
:bordered="true"
shape="rounded-square"
>
<VueIcon no-fill>
<Database />
</VueIcon>
<VueVisuallyHidden>Write the SQL to the Database</VueVisuallyHidden>
</VueButtonFx>
<VueButtonFx
fx="jelly"
fx-ease="spring-lg"
fx-speed="lg"
title="Warning Bordered"
variant="warning"
:bordered="true"
shape="rounded-square"
>
<VueIcon no-fill>
<Bomb />
</VueIcon>
<VueVisuallyHidden>Warning - you better be careful.</VueVisuallyHidden>
</VueButtonFx>
</div>
<!-- Composite Effect -->
<div class="mbe4">
<h2>Composite Effect</h2>
<p class="mbe2">Special multi-stage animation</p>
</div>
<div class="stacked-mobile mbe6">
<VueButtonFx
fx="pulse-wobble"
fx-speed="xl"
title="Pulse → Wobble"
variant="primary"
shape="rounded"
>
Pulse → Wobble
</VueButtonFx>
<VueButtonFx
fx="pulse-wobble"
fx-speed="xl"
title="Pulse → Wobble"
variant="success"
shape="rounded"
>
Pulse → Wobble
</VueButtonFx>
<VueButtonFx
fx="pulse-wobble"
fx-speed="xl"
title="Pulse → Wobble"
variant="monochrome"
shape="rounded"
>
Pulse → Wobble
</VueButtonFx>
<VueButtonFx
fx="pulse-wobble"
fx-speed="xl"
title="Pulse → Wobble"
variant="danger"
shape="rounded"
>
Pulse → Wobble
</VueButtonFx>
</div>
<!-- Speed Variations -->
<div class="mbe4">
<h2>Speed Variations</h2>
<p class="mbe2">Control animation speed with the fxSpeed prop</p>
</div>
<div class="stacked-mobile mbe6">
<VueButtonFx
fx="pulse"
fx-speed="xs"
title="XS"
variant="primary"
>XS</VueButtonFx>
<VueButtonFx
fx="pulse"
fx-speed="sm"
title="SM"
variant="primary"
>SM</VueButtonFx>
<VueButtonFx
fx="pulse"
fx-speed="md"
title="MD"
variant="primary"
>MD</VueButtonFx>
<VueButtonFx
fx="pulse"
fx-speed="lg"
title="LG"
variant="primary"
>LG</VueButtonFx>
<VueButtonFx
fx="pulse"
fx-speed="xl"
title="XL"
variant="primary"
>XL</VueButtonFx>
</div>
<!-- Easing Functions -->
<div class="mbe4">
<h2>Easing Functions</h2>
<p class="mbe2">Different easing functions create different animation feels</p>
<VueAlert :bordered-left="true">
Examples use <code>fx-speed="xl"</code> to make easing differences more visible.
For production, prefer <code>"sm"</code> or <code>"md"</code> speeds.
</VueAlert>
</div>
<div class="stacked-mobile mbe6">
<VueButtonFx
fx="bounce"
fx-ease="ease"
fx-speed="xl"
title="Ease"
size="sm"
variant="primary"
>Ease</VueButtonFx>
<VueButtonFx
fx="bounce"
fx-ease="ease-in"
fx-speed="xl"
title="Ease-In"
size="sm"
variant="primary"
>Ease-In</VueButtonFx>
<VueButtonFx
fx="bounce"
fx-ease="ease-out"
fx-speed="xl"
title="Ease-Out"
size="sm"
variant="primary"
>Ease-Out</VueButtonFx>
<VueButtonFx
fx="bounce"
fx-ease="bounce"
fx-speed="xl"
title="Bounce"
size="sm"
variant="primary"
>Bounce</VueButtonFx>
<VueButtonFx
fx="bounce"
fx-ease="spring-sm"
fx-speed="xl"
title="Spring SM"
size="sm"
variant="primary"
>Spring SM</VueButtonFx>
<VueButtonFx
fx="bounce"
fx-ease="spring-md"
fx-speed="xl"
title="Spring MD"
size="sm"
variant="primary"
>Spring MD</VueButtonFx>
<VueButtonFx
fx="bounce"
fx-ease="spring-lg"
fx-speed="xl"
title="Spring SM"
size="sm"
variant="primary"
>Spring LG</VueButtonFx>
</div>
<!-- Disabled State -->
<div class="mbe4">
<h2>Disabling Effects</h2>
<p class="example-description">
These buttons have <code>fx="bounce"</code> but <code>:fx-disabled="true"</code>
prevents the animation from playing while keeping the buttons clickable
</p>
</div>
<div class="stacked-mobile mbe6">
<VueButtonFx
fx="bounce"
:fx-disabled="true"
title="FX Disabled"
variant="primary"
>
FX Disabled
</VueButtonFx>
<VueButtonFx
fx="bounce"
:fx-disabled="true"
title="FX Disabled"
variant="secondary"
>
FX Disabled
</VueButtonFx>
</div>
</section>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { VueButtonFx } from "agnosticui-core/button-fx/vue";
import { VueIcon } from "agnosticui-core/icon/vue";
import { VueAlert } from "agnosticui-core/alert/vue";
import { VueVisuallyHidden } from "agnosticui-core/visually-hidden/vue";
import { Mail, Trash2, ShoppingCart, Database, Bomb } from "lucide-vue-next";
export default defineComponent({
name: "ButtonFxExamples",
components: {
Mail,
Trash2,
ShoppingCart,
Bomb,
Database,
VueButtonFx,
VueIcon,
VueVisuallyHidden,
VueAlert,
},
});
</script>
Live Preview
View Lit / Web Component Code
import { LitElement, html } from 'lit';
import 'agnosticui-core/button-fx';
import 'agnosticui-core/icon';
import 'agnosticui-core/alert';
export class ButtonFxLitExamples extends LitElement {
// Render in light DOM to access global utility classes
createRenderRoot() {
return this;
}
render() {
return html`
<section>
<!-- Hover Effects -->
<div class="mbe4">
<h2>Hover Effects</h2>
<p class="mbe2">These effects trigger on hover</p>
</div>
<div class="stacked-mobile mbe6">
<ag-button-fx fx="bounce" fx-ease="spring-md" title="Bounce" variant="primary" shape="rounded">
Bounce
</ag-button-fx>
<ag-button-fx fx="pulse" fx-ease="spring-md" title="Pulse" variant="success" shape="rounded">
Pulse
</ag-button-fx>
<ag-button-fx fx="jelly" fx-ease="spring-lg" fx-speed="lg" title="Jelly button" variant="warning" shape="rounded">
Jelly
</ag-button-fx>
<ag-button-fx fx="grow" fx-ease="spring-md" title="Grow button" variant="primary" shape="rounded">
Grow
</ag-button-fx>
<ag-button-fx fx="shrink" fx-ease="spring-md" title="Shrink button" variant="secondary" shape="rounded">
Shrink
</ag-button-fx>
</div>
<!-- Click Effects -->
<div class="mbe4">
<h2>Click Effects</h2>
<p class="mbe2">These effects trigger on click/active state</p>
</div>
<div class="stacked-mobile mbe6">
<ag-button-fx fx="press-pop" fx-ease="spring-sm" title="Press Pop" variant="primary" shape="rounded">
Press Pop
</ag-button-fx>
<ag-button-fx fx="press-pop" variant="monochrome" title="Send the email" shape="rounded-square" size="lg">
<ag-icon no-fill>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
</svg>
</ag-icon>
<span aria-label="Send the email" style="position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0;">Send the email</span>
</ag-button-fx>
<ag-button-fx fx="press-shadow" variant="warning" title="Press Shadow" shape="rounded">
Press Shadow
</ag-button-fx>
<ag-button-fx fx="press-shadow" variant="success" title="Press Shadow" shape="rounded">
Press Shadow
</ag-button-fx>
<ag-button-fx fx="press-shadow" variant="primary" title="Shopping cart button" shape="rounded-square" size="lg">
<ag-icon no-fill>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M9 2L1 8l8 6 8-6-8-6z"/>
<path d="M9 20V8M23 14l-8 6-8-6"/>
</svg>
</ag-icon>
<span aria-label="Proceed to your cart." style="position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0;">Proceed to your cart.</span>
</ag-button-fx>
<ag-button-fx fx="press-shadow" variant="danger" title="Dangerous action button" shape="rounded-square" size="lg">
<ag-icon no-fill>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<circle cx="12" cy="12" r="1"/>
<path d="M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83"/>
</svg>
</ag-icon>
<span aria-label="Do the dangerous thing" style="position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0;">Do the dangerous thing</span>
</ag-button-fx>
</div>
<!-- Background Effects -->
<div class="mbe4">
<h2>Background Effects</h2>
<p class="mbe2">Effects that animate the button background</p>
</div>
<div class="stacked-mobile mbe6">
<ag-button-fx fx="bg-slide" fx-speed="md" fx-ease="ease-out" title="BG Slide" variant="primary" shape="rounded">
BG Slide
</ag-button-fx>
<ag-button-fx fx="side-slide" fx-speed="md" fx-ease="ease-out" variant="success" shape="rounded">
Side Slide
</ag-button-fx>
</div>
<!-- Motion Effects -->
<div class="mbe4">
<h2>Motion Effects</h2>
<p class="mbe2">Dynamic movement effects</p>
</div>
<div class="stacked-mobile mbe6">
<ag-button-fx fx="wobble" fx-ease="spring-md" title="Wobble" variant="warning" shape="rounded">
Wobble
</ag-button-fx>
<ag-button-fx fx="shake" fx-speed="sm" title="Shake" variant="danger" shape="rounded">
Shake
</ag-button-fx>
<ag-button-fx fx="push" fx-ease="spring-sm" title="Push" variant="primary" shape="rounded">
Push
</ag-button-fx>
</div>
<!-- Bordered Buttons -->
<div class="mbe4">
<h2>Bordered Buttons</h2>
<p class="mbe2">Effects work with bordered button styles</p>
</div>
<div class="stacked-mobile mbe6">
<ag-button-fx fx="jelly" fx-ease="spring-lg" fx-speed="lg" title="Primary Bordered" variant="primary" bordered shape="rounded">
Primary
</ag-button-fx>
<ag-button-fx fx="jelly" fx-speed="lg" fx-ease="spring-lg" title="Success Bordered" variant="success" bordered shape="capsule">
Capsule
</ag-button-fx>
<ag-button-fx fx="jelly" fx-ease="spring-lg" fx-speed="lg" title="Monochrome Bordered" variant="monochrome" bordered shape="rounded-square">
<ag-icon no-fill>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6"/>
</svg>
</ag-icon>
<span aria-label="Toss it in the trash" style="position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0;">Toss it in the trash</span>
</ag-button-fx>
<ag-button-fx fx="jelly" fx-speed="lg" fx-ease="spring-lg" title="Danger Bordered" variant="danger" bordered shape="rounded-square">
<ag-icon no-fill>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<ellipse cx="12" cy="5" rx="9" ry="3"/>
<path d="M3 5v14a9 3 0 0018 0V5"/>
</svg>
</ag-icon>
<span aria-label="Write the SQL to the Database" style="position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0;">Write the SQL to the Database</span>
</ag-button-fx>
<ag-button-fx fx="jelly" fx-ease="spring-lg" fx-speed="lg" title="Warning Bordered" variant="warning" bordered shape="rounded-square">
<ag-icon no-fill>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<circle cx="12" cy="12" r="1"/>
<path d="M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83"/>
</svg>
</ag-icon>
<span aria-label="Warning - you better be careful." style="position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0;">Warning - you better be careful.</span>
</ag-button-fx>
</div>
<!-- Composite Effect -->
<div class="mbe4">
<h2>Composite Effect</h2>
<p class="mbe2">Special multi-stage animation</p>
</div>
<div class="stacked-mobile mbe6">
<ag-button-fx fx="pulse-wobble" fx-speed="xl" title="Pulse → Wobble" variant="primary" shape="rounded">
Pulse → Wobble
</ag-button-fx>
<ag-button-fx fx="pulse-wobble" fx-speed="xl" title="Pulse → Wobble" variant="success" shape="rounded">
Pulse → Wobble
</ag-button-fx>
<ag-button-fx fx="pulse-wobble" fx-speed="xl" title="Pulse → Wobble" variant="monochrome" shape="rounded">
Pulse → Wobble
</ag-button-fx>
<ag-button-fx fx="pulse-wobble" fx-speed="xl" title="Pulse → Wobble" variant="danger" shape="rounded">
Pulse → Wobble
</ag-button-fx>
</div>
<!-- Speed Variations -->
<div class="mbe4">
<h2>Speed Variations</h2>
<p class="mbe2">Control animation speed with the fxSpeed prop</p>
</div>
<div class="stacked-mobile mbe6">
<ag-button-fx fx="pulse" fx-speed="xs" title="XS" variant="primary">XS</ag-button-fx>
<ag-button-fx fx="pulse" fx-speed="sm" title="SM" variant="primary">SM</ag-button-fx>
<ag-button-fx fx="pulse" fx-speed="md" title="MD" variant="primary">MD</ag-button-fx>
<ag-button-fx fx="pulse" fx-speed="lg" title="LG" variant="primary">LG</ag-button-fx>
<ag-button-fx fx="pulse" fx-speed="xl" title="XL" variant="primary">XL</ag-button-fx>
</div>
<!-- Easing Functions -->
<div class="mbe4">
<h2>Easing Functions</h2>
<p class="mbe2">Different easing functions create different animation feels</p>
<ag-alert bordered-left>
Examples use <code>fx-speed="xl"</code> to make easing differences more visible.
For production, prefer <code>"sm"</code> or <code>"md"</code> speeds.
</ag-alert>
</div>
<div class="stacked-mobile mbe6">
<ag-button-fx fx="bounce" fx-ease="ease" fx-speed="xl" title="Ease" size="sm" variant="primary">Ease</ag-button-fx>
<ag-button-fx fx="bounce" fx-ease="ease-in" fx-speed="xl" title="Ease-In" size="sm" variant="primary">Ease-In</ag-button-fx>
<ag-button-fx fx="bounce" fx-ease="ease-out" fx-speed="xl" title="Ease-Out" size="sm" variant="primary">Ease-Out</ag-button-fx>
<ag-button-fx fx="bounce" fx-ease="bounce" fx-speed="xl" title="Bounce" size="sm" variant="primary">Bounce</ag-button-fx>
<ag-button-fx fx="bounce" fx-ease="spring-sm" fx-speed="xl" title="Spring SM" size="sm" variant="primary">Spring SM</ag-button-fx>
<ag-button-fx fx="bounce" fx-ease="spring-md" fx-speed="xl" title="Spring MD" size="sm" variant="primary">Spring MD</ag-button-fx>
<ag-button-fx fx="bounce" fx-ease="spring-lg" fx-speed="xl" title="Spring SM" size="sm" variant="primary">Spring LG</ag-button-fx>
</div>
<!-- Disabled State -->
<div class="mbe4">
<h2>Disabling Effects</h2>
<p class="example-description">
These buttons have <code>fx="bounce"</code> but <code>fx-disabled="true"</code>
prevents the animation from playing while keeping the buttons clickable
</p>
</div>
<div class="stacked-mobile mbe6">
<ag-button-fx fx="bounce" fx-disabled title="FX Disabled" variant="primary">
FX Disabled
</ag-button-fx>
<ag-button-fx fx="bounce" fx-disabled title="FX Disabled" variant="secondary">
FX Disabled
</ag-button-fx>
</div>
</section>
`;
}
}
// Register the custom element
customElements.define('buttonfx-lit-examples', ButtonFxLitExamples);
Interactive Preview: Click the "Open in StackBlitz" button below to see this example running live in an interactive playground.
View React Code
import { ReactButtonFx } from "agnosticui-core/button-fx/react";
import { ReactIcon } from "agnosticui-core/icon/react";
import { ReactAlert } from "agnosticui-core/alert/react";
import { ReactVisuallyHidden } from "agnosticui-core/visually-hidden/react";
import { Mail, Trash2, ShoppingCart, Database, Bomb } from "lucide-react";
export default function ButtonFxReactExamples() {
return (
<section>
{/* Hover Effects */}
<div className="mbe4">
<h2>Hover Effects</h2>
<p className="mbe2">These effects trigger on hover</p>
</div>
<div className="stacked-mobile mbe6">
<ReactButtonFx
fx="bounce"
fxEase="spring-md"
title="Bounce"
variant="primary"
shape="rounded"
>
Bounce
</ReactButtonFx>
<ReactButtonFx
fx="pulse"
fxEase="spring-md"
title="Pulse"
variant="success"
shape="rounded"
>
Pulse
</ReactButtonFx>
<ReactButtonFx
fx="jelly"
fxEase="spring-lg"
fxSpeed="lg"
title="Jelly button"
variant="warning"
shape="rounded"
>
Jelly
</ReactButtonFx>
<ReactButtonFx
fx="grow"
fxEase="spring-md"
title="Grow button"
variant="primary"
shape="rounded"
>
Grow
</ReactButtonFx>
<ReactButtonFx
fx="shrink"
fxEase="spring-md"
title="Shrink button"
variant="secondary"
shape="rounded"
>
Shrink
</ReactButtonFx>
</div>
{/* Click Effects */}
<div className="mbe4">
<h2>Click Effects</h2>
<p className="mbe2">These effects trigger on click/active state</p>
</div>
<div className="stacked-mobile mbe6">
<ReactButtonFx
fx="press-pop"
fxEase="spring-sm"
title="Press Pop"
variant="primary"
shape="rounded"
>
Press Pop
</ReactButtonFx>
<ReactButtonFx
fx="press-pop"
variant="monochrome"
title="Send the email"
shape="rounded-square"
size="lg"
>
<ReactIcon noFill>
<Mail size={24} />
</ReactIcon>
<ReactVisuallyHidden>Send the email</ReactVisuallyHidden>
</ReactButtonFx>
<ReactButtonFx
fx="press-shadow"
variant="warning"
title="Press Shadow"
shape="rounded"
>
Press Shadow
</ReactButtonFx>
<ReactButtonFx
fx="press-shadow"
variant="success"
title="Press Shadow"
shape="rounded"
>
Press Shadow
</ReactButtonFx>
<ReactButtonFx
fx="press-shadow"
variant="primary"
title="Shopping cart button"
shape="rounded-square"
size="lg"
>
<ReactIcon noFill>
<ShoppingCart size={24} />
</ReactIcon>
<ReactVisuallyHidden>Proceed to your cart.</ReactVisuallyHidden>
</ReactButtonFx>
<ReactButtonFx
fx="press-shadow"
variant="danger"
title="Dangerous action button"
shape="rounded-square"
size="lg"
>
<ReactIcon noFill>
<Bomb size={24} />
</ReactIcon>
<ReactVisuallyHidden>Do the dangerous thing</ReactVisuallyHidden>
</ReactButtonFx>
</div>
{/* Background Effects */}
<div className="mbe4">
<h2>Background Effects</h2>
<p className="mbe2">Effects that animate the button background</p>
</div>
<div className="stacked-mobile mbe6">
<ReactButtonFx
fx="bg-slide"
fxSpeed="md"
fxEase="ease-out"
title="BG Slide"
variant="primary"
shape="rounded"
>
BG Slide
</ReactButtonFx>
<ReactButtonFx
fx="side-slide"
fxSpeed="md"
fxEase="ease-out"
variant="success"
shape="rounded"
>
Side Slide
</ReactButtonFx>
</div>
{/* Motion Effects */}
<div className="mbe4">
<h2>Motion Effects</h2>
<p className="mbe2">Dynamic movement effects</p>
</div>
<div className="stacked-mobile mbe6">
<ReactButtonFx
fx="wobble"
fxEase="spring-md"
title="Wobble"
variant="warning"
shape="rounded"
>
Wobble
</ReactButtonFx>
<ReactButtonFx
fx="shake"
fxSpeed="sm"
title="Shake"
variant="danger"
shape="rounded"
>
Shake
</ReactButtonFx>
<ReactButtonFx
fx="push"
fxEase="spring-sm"
title="Push"
variant="primary"
shape="rounded"
>
Push
</ReactButtonFx>
</div>
{/* Bordered Buttons */}
<div className="mbe4">
<h2>Bordered Buttons</h2>
<p className="mbe2">Effects work with bordered button styles</p>
</div>
<div className="stacked-mobile mbe6">
<ReactButtonFx
fx="jelly"
fxEase="spring-lg"
fxSpeed="lg"
title="Primary Bordered"
variant="primary"
bordered
shape="rounded"
>
Primary
</ReactButtonFx>
<ReactButtonFx
fx="jelly"
fxSpeed="lg"
fxEase="spring-lg"
title="Success Bordered"
variant="success"
bordered
shape="capsule"
>
Capsule
</ReactButtonFx>
<ReactButtonFx
fx="jelly"
fxEase="spring-lg"
fxSpeed="lg"
title="Monochrome Bordered"
variant="monochrome"
bordered
shape="rounded-square"
>
<ReactIcon noFill>
<Trash2 size={24} />
</ReactIcon>
<ReactVisuallyHidden>Toss it in the trash</ReactVisuallyHidden>
</ReactButtonFx>
<ReactButtonFx
fx="jelly"
fxSpeed="lg"
fxEase="spring-lg"
title="Danger Bordered"
variant="danger"
bordered
shape="rounded-square"
>
<ReactIcon noFill>
<Database size={24} />
</ReactIcon>
<ReactVisuallyHidden>Write the SQL to the Database</ReactVisuallyHidden>
</ReactButtonFx>
<ReactButtonFx
fx="jelly"
fxEase="spring-lg"
fxSpeed="lg"
title="Warning Bordered"
variant="warning"
bordered
shape="rounded-square"
>
<ReactIcon noFill>
<Bomb size={24} />
</ReactIcon>
<ReactVisuallyHidden>Warning - you better be careful.</ReactVisuallyHidden>
</ReactButtonFx>
</div>
{/* Composite Effect */}
<div className="mbe4">
<h2>Composite Effect</h2>
<p className="mbe2">Special multi-stage animation</p>
</div>
<div className="stacked-mobile mbe6">
<ReactButtonFx
fx="pulse-wobble"
fxSpeed="xl"
title="Pulse → Wobble"
variant="primary"
shape="rounded"
>
Pulse → Wobble
</ReactButtonFx>
<ReactButtonFx
fx="pulse-wobble"
fxSpeed="xl"
title="Pulse → Wobble"
variant="success"
shape="rounded"
>
Pulse → Wobble
</ReactButtonFx>
<ReactButtonFx
fx="pulse-wobble"
fxSpeed="xl"
title="Pulse → Wobble"
variant="monochrome"
shape="rounded"
>
Pulse → Wobble
</ReactButtonFx>
<ReactButtonFx
fx="pulse-wobble"
fxSpeed="xl"
title="Pulse → Wobble"
variant="danger"
shape="rounded"
>
Pulse → Wobble
</ReactButtonFx>
</div>
{/* Speed Variations */}
<div className="mbe4">
<h2>Speed Variations</h2>
<p className="mbe2">Control animation speed with the fxSpeed prop</p>
</div>
<div className="stacked-mobile mbe6">
<ReactButtonFx fx="pulse" fxSpeed="xs" title="XS" variant="primary">
XS
</ReactButtonFx>
<ReactButtonFx fx="pulse" fxSpeed="sm" title="SM" variant="primary">
SM
</ReactButtonFx>
<ReactButtonFx fx="pulse" fxSpeed="md" title="MD" variant="primary">
MD
</ReactButtonFx>
<ReactButtonFx fx="pulse" fxSpeed="lg" title="LG" variant="primary">
LG
</ReactButtonFx>
<ReactButtonFx fx="pulse" fxSpeed="xl" title="XL" variant="primary">
XL
</ReactButtonFx>
</div>
{/* Easing Functions */}
<div className="mbe4">
<h2>Easing Functions</h2>
<p className="mbe2">Different easing functions create different animation feels</p>
<ReactAlert borderedLeft>
Examples use <code>fxSpeed="xl"</code> to make easing differences more visible.
For production, prefer <code>"sm"</code> or <code>"md"</code> speeds.
</ReactAlert>
</div>
<div className="stacked-mobile mbe6">
<ReactButtonFx
fx="bounce"
fxEase="ease"
fxSpeed="xl"
title="Ease"
size="sm"
variant="primary"
>
Ease
</ReactButtonFx>
<ReactButtonFx
fx="bounce"
fxEase="ease-in"
fxSpeed="xl"
title="Ease-In"
size="sm"
variant="primary"
>
Ease-In
</ReactButtonFx>
<ReactButtonFx
fx="bounce"
fxEase="ease-out"
fxSpeed="xl"
title="Ease-Out"
size="sm"
variant="primary"
>
Ease-Out
</ReactButtonFx>
<ReactButtonFx
fx="bounce"
fxEase="bounce"
fxSpeed="xl"
title="Bounce"
size="sm"
variant="primary"
>
Bounce
</ReactButtonFx>
<ReactButtonFx
fx="bounce"
fxEase="spring-sm"
fxSpeed="xl"
title="Spring SM"
size="sm"
variant="primary"
>
Spring SM
</ReactButtonFx>
<ReactButtonFx
fx="bounce"
fxEase="spring-md"
fxSpeed="xl"
title="Spring MD"
size="sm"
variant="primary"
>
Spring MD
</ReactButtonFx>
<ReactButtonFx
fx="bounce"
fxEase="spring-lg"
fxSpeed="xl"
title="Spring SM"
size="sm"
variant="primary"
>
Spring LG
</ReactButtonFx>
</div>
{/* Disabled State */}
<div className="mbe4">
<h2>Disabling Effects</h2>
<p className="example-description">
These buttons have <code>fx="bounce"</code> but <code>fxDisabled={"{true}"}</code>
prevents the animation from playing while keeping the buttons clickable
</p>
</div>
<div className="stacked-mobile mbe6">
<ReactButtonFx
fx="bounce"
fxDisabled
title="FX Disabled"
variant="primary"
>
FX Disabled
</ReactButtonFx>
<ReactButtonFx
fx="bounce"
fxDisabled
title="FX Disabled"
variant="secondary"
>
FX Disabled
</ReactButtonFx>
</div>
</section>
);
}
Usage
TIP
The framework examples below import AgnosticUI as an npm package. Alternatively, you can use the CLI for complete control, AI/LLM visibility, and full code ownership:
npx ag init --framework FRAMEWORK # react, vue, lit, svelte, etc.
npx ag add ButtonFxThe CLI copies source code directly into your project, giving you full visibility and control. After running npx ag add, you'll receive exact import instructions.
Vue
<template>
<VueButtonFx
fx="bounce"
fx-ease="spring-md"
variant="primary"
shape="rounded"
>
Hover Me
</VueButtonFx>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { VueButtonFx } from "agnosticui-core/button-fx/vue";
export default defineComponent({
components: { VueButtonFx },
});
</script>React
import { ReactButtonFx } from "agnosticui-core/button-fx/react";
export default function Example() {
return (
<ReactButtonFx
fx="bounce"
fxEase="spring-md"
variant="primary"
shape="rounded"
>
Hover Me
</ReactButtonFx>
);
}Lit (Web Components)
<script type="module">
import "agnosticui-core/button-fx";
</script>
<ag-button-fx fx="bounce" fx-ease="spring-md" variant="primary" shape="rounded">
Hover Me
</ag-button-fx>Available Effects
Hover Effects
- bounce - Vertical pop animation
- pulse - Scale grow effect
- jelly - Squash and stretch animation
- grow - Scale up
- shrink - Scale down
- push - Press down effect
- bg-slide - Background slides up
- side-slide - Background wipes left to right
- wobble - Rotate wobble
- shake - Horizontal shake
Click/Active Effects
- press-pop - Quick press animation
- press-shadow - Shadow press effect
Mount Effects
- slide-in - Entrance animation
Composite Effects
- pulse-wobble - Combines pulse and wobble effects sequentially. For this effect it's recommended to use a slower
fx-speed.
Props
FX Props
| Prop | Type | Default | Description |
|---|---|---|---|
fx | string | string[] | '' | Effect name(s) to apply. Can be a single effect or array of effects |
fxSpeed | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Animation duration speed |
fxEase | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'bounce' | 'spring-sm' | 'spring-md' | 'spring-lg' | 'ease' | Animation easing function |
fxDisabled | boolean | false | Disable FX effects entirely |
Button Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'monochrome' | '' | Visual style of the button |
size | 'x-sm' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Size of the button |
shape | 'capsule' | 'rounded' | 'circle' | 'square' | 'rounded-square' | '' | Shape of the button |
bordered | boolean | false | Applies a bordered style with transparent background |
ghost | boolean | false | Minimal button with transparent background |
link | boolean | false | Link-style button with underline on hover |
type | 'button' | 'submit' | 'reset' | 'button' | Button type for form behavior |
disabled | boolean | false | Disables the button |
loading | boolean | false | Shows a loading state |
Events
| Event | Payload | Description |
|---|---|---|
toggle | CustomEvent | Fired when button is clicked/toggled |
focus | FocusEvent | Fired when button receives focus |
blur | FocusEvent | Fired when button loses focus |
Examples
Effect Combinations
You can combine multiple effects by passing an array:
Vue
<VueButtonFx :fx="['pulse', 'glow']" variant="primary">
Multiple Effects
</VueButtonFx>React
<ReactButtonFx fx={["pulse", "glow"]} variant="primary">
Multiple Effects
</ReactButtonFx>Speed Variations
Control animation speed with the fxSpeed prop:
Vue
<VueButtonFx fx="pulse" fx-speed="xs" variant="primary">XS Speed</VueButtonFx>
<VueButtonFx fx="pulse" fx-speed="sm" variant="primary">SM Speed</VueButtonFx>
<VueButtonFx fx="pulse" fx-speed="md" variant="primary">MD Speed</VueButtonFx>
<VueButtonFx fx="pulse" fx-speed="lg" variant="primary">LG Speed</VueButtonFx>
<VueButtonFx fx="pulse" fx-speed="xl" variant="primary">XL Speed</VueButtonFx>Easing Functions
Customize the animation feel with different easing functions:
Vue
<VueButtonFx
fx="bounce"
fx-ease="spring-sm"
variant="primary"
>Spring Small</VueButtonFx>
<VueButtonFx
fx="bounce"
fx-ease="spring-md"
variant="primary"
>Spring Medium</VueButtonFx>
<VueButtonFx
fx="bounce"
fx-ease="spring-lg"
variant="primary"
>Spring Large</VueButtonFx>
<VueButtonFx fx="bounce" fx-ease="bounce" variant="primary">Bounce</VueButtonFx>Composite Effect - Pulse Wobble
The special pulse-wobble effect creates a two-stage animation:
Vue
<VueButtonFx fx="pulse-wobble" variant="primary" shape="rounded">
Pulse → Wobble
</VueButtonFx>React
<ReactButtonFx fx="pulse-wobble" variant="primary" shape="rounded">
Pulse → Wobble
</ReactButtonFx>Lit (Web Components)
<ag-button-fx fx="pulse-wobble" variant="primary" shape="rounded">
Pulse → Wobble
</ag-button-fx>Disabling Effects
You can disable effects while keeping the button functional applying :fx-disabled="true" which prevents the animation from playing while keeping the button clickable
Vue
<VueButtonFx fx="bounce" :fx-disabled="true" variant="primary">
No Animation
</VueButtonFx>Accessibility
- Reduced Motion: All effects automatically respect the
prefers-reduced-motionmedia query. When users have reduced motion enabled in their OS settings, animations are disabled. - Keyboard Navigation: ButtonFx maintains full keyboard accessibility with proper focus states.
- Screen Readers: The component uses semantic HTML button elements that work correctly with assistive technologies.
- Focus Indicators: Clear focus states are maintained even with effects applied.
- Color Contrast: All button variants meet WCAG AA contrast requirements.
Best Practices
- Choose Appropriate Effects: Match effects to button purpose (e.g.,
shakefor errors,pulsefor primary actions) - Performance: Limit the number of animated buttons on a single page for optimal performance
- Consistency: Use consistent effects across similar actions in your application
- Subtlety: Start with medium speeds and springs; adjust based on user testing
- Testing: Always test with
prefers-reduced-motionenabled to ensure graceful degradation
Browser Support
ButtonFx uses modern CSS features and is supported in all evergreen browsers:
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
Animations gracefully degrade in older browsers while maintaining functionality.