@rcaferati/react-awesome-button provides three related button components:
AwesomeButtonβ animated base buttonAwesomeButtonProgressβ progress flow wrapper on top ofAwesomeButtonAwesomeButtonSocialβ social/share wrapper on top ofAwesomeButton
This README is updated for the current component patterns and prop behavior.
npm install @rcaferati/react-awesome-buttonimport React from 'react';
import { AwesomeButton } from '@rcaferati/react-awesome-button';
import '@rcaferati/react-awesome-button/styles.css';
export default function Example() {
return <AwesomeButton type="primary">Button</AwesomeButton>;
}If you want to use the package theme module object (for cssModule), import a built theme module and pass it to the component.
Note: depending on your bundler/module interop, the imported theme may be on
.default.
import React from 'react';
import { AwesomeButton } from '@rcaferati/react-awesome-button';
import themeBlue from '@rcaferati/react-awesome-button/themes/theme-blue';
const blueTheme = themeBlue?.default ?? themeBlue;
export default function Example() {
return (
<AwesomeButton cssModule={blueTheme} type="primary">
Button
</AwesomeButton>
);
}If href is not provided, AwesomeButton renders a button-like element and calls onPress on release.
import React from 'react';
import { AwesomeButton } from '@rcaferati/react-awesome-button';
import themeBlue from '@rcaferati/react-awesome-button/themes/theme-blue';
const blueTheme = themeBlue?.default ?? themeBlue;
export default function Example() {
return (
<AwesomeButton
cssModule={blueTheme}
type="primary"
onPress={() => {
// do something
}}>
Button
</AwesomeButton>
);
}If href is provided, it renders anchor-like behavior and lets native navigation happen.
import React from 'react';
import { AwesomeButton } from '@rcaferati/react-awesome-button';
import themeBlue from '@rcaferati/react-awesome-button/themes/theme-blue';
const blueTheme = themeBlue?.default ?? themeBlue;
export default function Example() {
return (
<AwesomeButton
cssModule={blueTheme}
type="primary"
href="https://example.com"
containerProps={{ target: '_blank', rel: 'noreferrer noopener' }}>
Open website
</AwesomeButton>
);
}Use before / after to render icons.
For icon-only buttons, pass the icon using before and omit children.
import React from 'react';
import { Play, ArrowRight, Sparkles } from 'lucide-react';
import { AwesomeButton } from '@rcaferati/react-awesome-button';
import themeBlue from '@rcaferati/react-awesome-button/themes/theme-blue';
const blueTheme = themeBlue?.default ?? themeBlue;
export default function Example() {
return (
<div style={{ display: 'grid', gap: 12 }}>
<AwesomeButton
cssModule={blueTheme}
type="primary"
size="medium"
before={<Sparkles size={16} aria-hidden="true" />}
after={<ArrowRight size={16} aria-hidden="true" />}>
Continue
</AwesomeButton>
{/* Icon-only button */}
<AwesomeButton
cssModule={blueTheme}
type="primary"
size="medium"
before={<Play size={16} aria-hidden="true" />}
/>
</div>
);
}size="small" | "medium" | "large"β fixed-size buttonsize={null}β auto width (content-driven width)
import React from 'react';
import { AwesomeButton } from '@rcaferati/react-awesome-button';
export default function Example() {
return (
<div style={{ display: 'grid', gap: 12 }}>
<AwesomeButton size="small" type="primary">
Small
</AwesomeButton>
<AwesomeButton size="medium" type="primary">
Medium
</AwesomeButton>
<AwesomeButton size="large" type="primary">
Large
</AwesomeButton>
<AwesomeButton size={null} type="primary">
Auto width grows with content
</AwesomeButton>
</div>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
type |
string |
'primary' |
Visual variant key (styled by theme/class names) |
size |
string | null |
null |
Button size key ('small', 'medium', 'large') 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 |
true |
If true and children is empty, renders placeholder/disabled state |
between |
boolean |
false |
Uses space-between layout for content (useful with icons) |
ripple |
boolean |
false |
Enables ripple effect on successful press release |
moveEvents |
boolean |
true |
Enables pointer move position classes (left/middle/right) |
href |
string | null |
null |
Enables anchor-like mode |
element |
React component | null |
null |
Custom forwarded root element component |
rootElement |
string |
'aws-btn' |
Base class prefix |
className |
string | null |
null |
Extra class names |
style |
React.CSSProperties |
{} |
Inline styles for root element |
containerProps |
object |
{} |
Additional props forwarded to root element |
cssModule |
Record<string, string> | null |
null |
CSS module mapping (theme object) |
before |
React.ReactNode |
null |
Content rendered before label |
after |
React.ReactNode |
null |
Content rendered after label |
extra |
React.ReactNode |
null |
Extra content rendered inside wrapper (used by wrappers like Progress) |
children |
React.ReactNode |
null |
Main label/content |
onPress |
(event) => void |
null |
Called on press release/activation |
onPressed |
(event) => void |
null |
Called when press-in animation completes |
onReleased |
(element: HTMLElement) => void |
null |
Called when release cycle is cleared |
onMouseDown |
(event) => void |
null |
Pointer/mouse/touch down callback |
onMouseUp |
(event) => void |
null |
Pointer/mouse/touch up callback |
AwesomeButtonProgress wraps AwesomeButton and manages a progress lifecycle.
Its onPress receives a second callback argument:
next(true)β success flownext(false, 'Failed')β error flow
import React from 'react';
import { AwesomeButtonProgress } from '@rcaferati/react-awesome-button';
import themeBlue from '@rcaferati/react-awesome-button/themes/theme-blue';
const blueTheme = themeBlue?.default ?? themeBlue;
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export default function Example() {
return (
<AwesomeButtonProgress
cssModule={blueTheme}
type="primary"
loadingLabel="Verifyingβ¦"
resultLabel="Verified!"
releaseDelay={500}
onPress={async (_event, next) => {
await sleep(900);
next(true);
}}>
Verify
</AwesomeButtonProgress>
);
}import React from 'react';
import { AwesomeButtonProgress } from '@rcaferati/react-awesome-button';
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export default function Example() {
return (
<AwesomeButtonProgress
type="danger"
loadingLabel="Publishingβ¦"
resultLabel="Done!"
onPress={async (_event, next) => {
await sleep(900);
next(false, 'Failed');
}}>
Publish
</AwesomeButtonProgress>
);
}import React from 'react';
import { Shield } from 'lucide-react';
import { AwesomeButtonProgress } from '@rcaferati/react-awesome-button';
import themeBlue from '@rcaferati/react-awesome-button/themes/theme-blue';
const blueTheme = themeBlue?.default ?? themeBlue;
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export default function Example() {
return (
<AwesomeButtonProgress
cssModule={blueTheme}
type="primary"
size="medium"
before={<Shield size={16} aria-hidden="true" />}
loadingLabel="Verifyingβ¦"
resultLabel="Verified!"
onPress={async (_event, next) => {
await sleep(900);
next(true);
}}>
Verify signature
</AwesomeButtonProgress>
);
}
AwesomeButtonProgressaccepts allAwesomeButtonprops exceptactiveand replacesonPresswith the progress version below.
| Prop | Type | Default | Description |
|---|---|---|---|
onPress |
(event, next) => void |
null |
Progress action handler. Call next(true) or next(false, label?) |
loadingLabel |
string |
'Wait..' |
Loading phase label |
resultLabel |
string |
'Success!' |
Success label |
releaseDelay |
number |
500 |
Delay before reset after progress end |
AwesomeButtonSocial wraps AwesomeButton and builds a social/share action when no custom onPress is provided.
On press, the component follows this order:
- If you provide
onPress, your handler is used (full override) - If
hrefis provided, native anchor navigation is used - Otherwise it builds a share payload and:
- tries
navigator.share(...)on mobile (when supported) - falls back to popup/window share (or direct URL fallback for some types like
instagram)
- tries
import React from 'react';
import { Github } from 'lucide-react';
import { AwesomeButtonSocial } from '@rcaferati/react-awesome-button';
import themeBlue from '@rcaferati/react-awesome-button/themes/theme-blue';
const blueTheme = themeBlue?.default ?? themeBlue;
export default function Example() {
return (
<AwesomeButtonSocial
cssModule={blueTheme}
type="github"
before={<Github size={16} aria-hidden="true" />}
sharer={{
url: 'https://example.com',
message: 'Check this out',
}}>
GitHub
</AwesomeButtonSocial>
);
}import React from 'react';
import { AwesomeButtonSocial } from '@rcaferati/react-awesome-button';
export default function Example() {
return (
<AwesomeButtonSocial
type="whatsapp"
sharer={{
phone: '5511999999999',
message: 'Hello from AwesomeButton',
url: 'https://example.com',
}}>
WhatsApp
</AwesomeButtonSocial>
);
}instagram is treated as a direct URL fallback (no dedicated web popup sharer endpoint).
import React from 'react';
import { AwesomeButtonSocial } from '@rcaferati/react-awesome-button';
export default function Example() {
return (
<AwesomeButtonSocial
type="instagram"
sharer={{
url: 'https://example.com',
message: 'Open this link',
}}>
Instagram
</AwesomeButtonSocial>
);
}If href is present, the component behaves like an anchor and does not execute the share flow.
import React from 'react';
import { AwesomeButtonSocial } from '@rcaferati/react-awesome-button';
export default function Example() {
return (
<AwesomeButtonSocial
type="github"
href="https://github.com/your-org/your-repo"
containerProps={{ target: '_blank', rel: 'noreferrer noopener' }}>
Open GitHub
</AwesomeButtonSocial>
);
}
AwesomeButtonSocialaccepts allAwesomeButtonprops and adds the props below.
| Prop | Type | Default | Description |
|---|---|---|---|
sharer |
object |
{} |
Share payload source (falls back to page metadata when omitted) |
dimensions |
{ width: number; height: number } |
{ width: 640, height: 480 } |
Popup window dimensions for share flows |
sharer.url |
string |
current page URL | URL to share (falls back to window.location.href) |
sharer.message |
string |
page title | Share message/text (falls back to document title) |
sharer.image |
string |
og:image meta |
Image URL used by supported sharers (e.g. Pinterest) |
sharer.phone |
string |
null |
Phone for WhatsApp |
sharer.user |
string |
null |
Username for Messenger direct flow |
The built-in sharer currently recognizes these values:
facebooktwitterpinterestlinkedinredditwhatsappmessengermailinstagram
Any other value can still be used as a visual button type, but the built-in share payload may return empty if the sharer type is unsupported.
When using the theme module import, some bundlers expose the object as default.
This pattern is safe:
const blueTheme = themeBlue?.default ?? themeBlue;Then pass it to any button component via:
<AwesomeButton cssModule={blueTheme}>Button</AwesomeButton>Use before and omit children:
<AwesomeButton before={<Play size={16} aria-hidden="true" />} />Use onPress={async (_event, next) => { ...; next(true|false); }}
Do not pass manual loading props to AwesomeButtonProgress.
Use before for icons (e.g. Lucide icons).
The social component does not need built-in icon usage to work.
Rafael Caferati
Website: caferati.dev
LinkedIn: linkedin.com/rcaferati
Instagram: instagram.com/rcaferati
MIT