A beautiful, customizable 3D button component for React with Next.js support, toggle mode, multiple themes, and easy CSS variable customization.
๐ Live Demo & Documentation โ
- ๐จ Multiple Pre-built Themes - Ocean, Sunset, Forest, Pirate, Neon, and Default
- ๐ญ Easy Customization - Override CSS variables for complete control
- ๐ฑ Mobile Optimized - Enhanced touch support with fixed mobile interaction issues
- โก Next.js Compatible - Works seamlessly with Next.js 13+ and App Router
- ๐ฏ TypeScript Support - Full TypeScript definitions included
- ๐ช Rich Interactions - 3D press effects, ripple animations, hover states
- ๐ Toggle Mode - Built-in toggle/switch functionality with smooth animations
- โฟ Accessible - Proper ARIA attributes and keyboard navigation
- ๐ฆ Tree-shakeable - ESM and CJS builds for optimal bundle size (~24KB)
- ๐จ 9 Button Variants - Primary, Secondary, Tertiary, Success, Error, Warning, Info, Anchor, Danger
- ๐ Zero Dependencies - No runtime dependencies, pure React component
Perfect for:
- โ Landing pages and marketing sites
- โ SaaS dashboards and admin panels
- โ E-commerce checkout flows
- โ Gaming and entertainment apps
- โ Form submissions and CTAs
- โ Mobile-first web applications
npm install react-3d-button
# or
yarn add react-3d-button
# or
pnpm add react-3d-buttonimport { Button3D } from 'react-3d-button';
import 'react-3d-button/styles';
function App() {
return (
<Button3D type="primary" onPress={() => console.log('Pressed!')}>
Click Me!
</Button3D>
);
}'use client';
import { Button3D } from 'react-3d-button';
import 'react-3d-button/styles';
export default function MyComponent() {
return (
<Button3D type="primary" onPress={() => alert('Hello!')}>
Press Me
</Button3D>
);
}React 3D Button supports two ways to apply themes: global (affects all buttons) or scoped (affects specific sections).
Apply a theme globally to all buttons in your app by importing the .global.css variant:
import { Button3D } from 'react-3d-button';
import 'react-3d-button/styles';
import 'react-3d-button/themes/pirate.global.css'; // โก Applies to ALL buttons
function App() {
return (
<>
<Button3D type="primary">Pirate Button</Button3D>
<Button3D type="success">Also Pirate</Button3D>
</>
);
}Apply themes to specific sections by wrapping buttons in a theme class:
import { Button3D } from 'react-3d-button';
import 'react-3d-button/styles';
import 'react-3d-button/themes/ocean.css'; // Scoped theme
import 'react-3d-button/themes/sunset.css'; // Another scoped theme
function App() {
return (
<>
<div className="theme-ocean">
<Button3D type="primary">Ocean Button</Button3D>
</div>
<div className="theme-sunset">
<Button3D type="primary">Sunset Button</Button3D>
</div>
</>
);
}| Theme | Global Import | Scoped Import | Description |
|---|---|---|---|
| Ocean | react-3d-button/themes/ocean.global.css |
react-3d-button/themes/ocean.css |
Cool blues and teals - perfect for marine or tech apps |
| Sunset | react-3d-button/themes/sunset.global.css |
react-3d-button/themes/sunset.css |
Warm oranges and purples - energetic and vibrant |
| Forest | react-3d-button/themes/forest.global.css |
react-3d-button/themes/forest.css |
Earthy greens and browns - natural and calming |
| Pirate | react-3d-button/themes/pirate.global.css |
react-3d-button/themes/pirate.css |
Rich browns and tans - adventurous theme |
| Neon | react-3d-button/themes/neon.global.css |
react-3d-button/themes/neon.css |
Vibrant neon colors - bold and modern |
๐ Preview all themes live โ
Override CSS variables to create your own theme:
/* custom-theme.css */
.aws-btn {
/* Primary button colors */
--button-primary-color: #your-color;
--button-primary-color-dark: #darker-shade;
--button-primary-color-light: #text-color;
--button-primary-color-hover: #hover-color;
/* 3D effect customization */
--button-raise-level: 6px; /* Height of the 3D effect */
--button-hover-pressure: 3; /* Intensity of hover tilt */
/* Border radius */
--button-default-border-radius: 8px;
/* Typography */
--button-font-family: 'Your Font', sans-serif;
--button-font-weight: 700;
/* And many more... see full list below */
}| Prop | Type | Default | Description |
|---|---|---|---|
type |
'primary' | 'secondary' | 'tertiary' | 'success' | 'error' | 'warning' | 'info' | 'anchor' | 'danger' |
'primary' |
Button variant |
size |
'small' | 'medium' | 'large' | string |
undefined |
Button size |
disabled |
boolean |
false |
Disable the button |
active |
boolean |
false |
Keep button in pressed state (controlled mode for toggles) |
defaultActive |
boolean |
false |
Initial active state (uncontrolled mode for toggles) |
toggle |
boolean |
false |
Enable toggle mode for persistent pressed states |
onChange |
(active: boolean) => void |
undefined |
Callback when toggle state changes |
visible |
boolean |
true |
Control button visibility |
ripple |
boolean |
false |
Enable ripple effect on press |
moveEvents |
boolean |
true |
Enable 3D tilt on mouse move |
href |
string |
undefined |
Render as anchor tag with href |
onPress |
(event) => void |
undefined |
Callback when button is pressed |
onPressed |
(event) => void |
undefined |
Callback when press animation starts |
onReleased |
(element) => void |
undefined |
Callback when button is released |
onMouseDown |
(event) => void |
undefined |
Mouse down event handler |
onMouseUp |
(event) => void |
undefined |
Mouse up event handler |
before |
ReactNode |
undefined |
Content before children (e.g., icon) |
after |
ReactNode |
undefined |
Content after children (e.g., icon) |
between |
boolean |
false |
Space between before/after content |
className |
string |
undefined |
Additional CSS classes |
style |
CSSProperties |
undefined |
Inline styles |
placeholder |
boolean |
true |
Show placeholder when no children |
containerProps |
HTMLAttributes |
{} |
Props passed to container element |
cssModule |
any |
undefined |
CSS module object for scoped styles |
<Button3D type="primary">Primary</Button3D>
<Button3D type="secondary">Secondary</Button3D>
<Button3D type="tertiary">Tertiary</Button3D>
<Button3D type="success">Success</Button3D>
<Button3D type="error">Error</Button3D>
<Button3D type="warning">Warning</Button3D>
<Button3D type="info">Info</Button3D>
<Button3D type="danger">Danger</Button3D><Button3D size="small">Small</Button3D>
<Button3D size="medium">Medium</Button3D>
<Button3D size="large">Large</Button3D>import { ArrowRight, Download } from 'lucide-react';
<Button3D
type="primary"
before={<Download size={16} />}
>
Download
</Button3D>
<Button3D
type="primary"
after={<ArrowRight size={16} />}
>
Next
</Button3D><Button3D href="https://example.com" type="primary">
Visit Website
</Button3D><Button3D type="primary" ripple={true} onPress={() => console.log('Pressed!')}>
Click for Ripple
</Button3D>const [isActive, setIsActive] = useState(false);
<Button3D
type="primary"
active={isActive}
onPress={() => setIsActive(!isActive)}
>
Toggle Active
</Button3D>;Transform buttons into interactive toggle switches with persistent pressed states:
// Uncontrolled toggle (manages its own state)
<Button3D
type="success"
toggle
defaultActive={false}
onChange={(active) => console.log('Toggle state:', active)}
>
Click to Toggle
</Button3D>
// Controlled toggle (you manage the state)
const [isEnabled, setIsEnabled] = useState(false);
<Button3D
type="primary"
toggle
active={isEnabled}
onChange={setIsEnabled}
>
{isEnabled ? 'โ Enabled' : 'Disabled'}
</Button3D>
// Toggle with icons (Lucide React example)
import { Check, Circle } from 'lucide-react';
const [notifications, setNotifications] = useState(true);
<Button3D
type="success"
toggle
active={notifications}
onChange={setNotifications}
>
{notifications ? <><Check size={16} /> ON</> : <><Circle size={16} /> OFF</>}
</Button3D>
// Settings panel example
<Button3D
type={darkMode ? 'primary' : 'secondary'}
toggle
active={darkMode}
onChange={setDarkMode}
size="small"
>
{darkMode ? '๐ Dark' : 'โ๏ธ Light'}
</Button3D>--button-default-height: 48px;
--button-default-font-size: 14px;
--button-default-border-radius: 6px;
--button-horizontal-padding: 20px;
--button-vertical-padding: 8px;--button-raise-level: 5px; /* Height of 3D effect */
--button-pressed-level: 0px; /* Depth when pressed */
--button-hover-pressure: 2; /* Hover tilt intensity (1-4) */
--transform-speed: 0.185s; /* Animation speed */
--button-transition-duration: 0.3s; /* General transitions */--button-font-family: inherit;
--button-font-weight: 600;
--button-letter-spacing: 0px;
--button-text-transform: none; /* or 'uppercase' */--button-ripple-color: rgba(255, 255, 255, 0.4);
--button-ripple-duration: 600ms;For each button type (primary, secondary, tertiary, success, error, warning, info, anchor, danger), you can customize:
/* Replace {type} with: primary, secondary, etc. */
--button-{type}-color: #hex; /* Main background color */
--button-{type}-color-dark: #hex; /* 3D shadow/pressed color (darker shade) */
--button-{type}-color-light: #hex; /* Text and icon color */
--button-{type}-color-hover: #hex; /* Background on hover */
--button-{type}-border: none; /* Border style (e.g., '1px solid #hex') */Example - Custom Primary Button:
.aws-btn {
--button-primary-color: #10b981; /* Green background */
--button-primary-color-dark: #059669; /* Darker green shadow */
--button-primary-color-light: #ffffff; /* White text */
--button-primary-color-hover: #0d9668; /* Hover state */
--button-raise-level: 8px; /* More pronounced 3D */
}For a complete list of all available CSS variables, check the source styles.css or try the interactive customizer on the demo site.
Make sure to import the base styles:
import 'react-3d-button/styles';Ensure you've wrapped your Next.js component with 'use client' directive:
'use client';
import { Button3D } from 'react-3d-button';If you encounter type errors with the style prop when using CSS variables:
<div style={{ '--button-primary-color': '#ff0000' } as React.CSSProperties}>
<Button3D type="primary">Custom Color</Button3D>
</div>Themes use CSS cascade, so import order matters:
// โ
Correct order
import 'react-3d-button/styles'; // Base styles first
import 'react-3d-button/themes/ocean.css'; // Theme second
// โ Wrong order
import 'react-3d-button/themes/ocean.css';
import 'react-3d-button/styles'; // This will override the themeThis component is built on top of the excellent react-awesome-button library by @rcaferati.
- โ Next.js Compatibility - Fixed issues with Next.js 13+ App Router and SSR
- โ Mobile Touch Support - Resolved touch event handling issues on mobile devices
- โ More Button Variants - Added tertiary, success, error, warning, and info types
- โ Enhanced Theme System - Easy-to-use CSS variable system for customization
- โ TypeScript Improvements - Better type definitions and prop validation
- โ Performance Optimizations - Improved rendering and event handling
- โ Scoped Themes - Support for applying different themes to different sections
MIT ยฉ Furkan Boran
Original react-awesome-button: MIT ยฉ @rcaferati
Contributions, issues, and feature requests are welcome!
Give a โญ๏ธ if this project helped you!
- GitHub: @boranfurkan
- Live Demo: https://react-3d-button-demo.vercel.app/
Made with โค๏ธ and inspired by react-awesome-button