A lightweight React hook for creating magnetic hover effects and interactive pull animations.
npm install use-attractuseMobile helper
jsx
'use client';
import { useAttract } from 'use-attract';
function MagneticButton() {
const { ref, style } = useAttract();
return (
ref={ref}
style={{
...style,
padding: '12px 24px',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
}}
>
Hover me! ð§ē
);
}
`
---
ðĶ Installation
`bash
npm install use-attract
`
`bash
yarn add use-attract
`
`bash
pnpm add use-attract
`
---
ðŊ Usage
$3
`jsx
'use client'; // Next.js App Router
import { useAttract, useMobile } from 'use-attract';
export default function AttractDemo() {
const { ref, style } = useAttract({
strength: 50, // How strong the magnetic pull is
magneticField: 32, // Distance in pixels where the effect activates
lerpFactor: 0.2, // Smoothness of the animation (0-1)
});
const isMobile = useMobile(1280); // Detect mobile screens
return (
ref={ref}
style={{
...style,
width: '120px',
height: '120px',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '12px',
cursor: 'pointer',
transition: 'box-shadow 0.3s ease',
}}
onMouseEnter={(e) => e.target.style.boxShadow = '0 20px 40px rgba(0,0,0,0.2)'}
onMouseLeave={(e) => e.target.style.boxShadow = 'none'}
>
ð§ē Magnetic
{isMobile !== undefined && (
Mobile detected: {isMobile ? 'Yes' : 'No'}
)}
$3
`jsx
const { ref, style, position } = useAttract({
enabled: true, // Enable/disable the effect
strength: 75, // Pull strength (0-100+)
magneticField: 50, // Activation radius in pixels
lerpFactor: 0.15, // Animation smoothness (lower = smoother)
});
// Access raw position data if needed
console.log(position); // { x: number, y: number }
`
---
ð API Reference
$3
Creates a magnetic hover effect for an element.
#### Parameters
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| enabled | boolean | true | Enable or disable the magnetic effect |
| strength | number | 50 | Strength of the magnetic pull (0-100+) |
| magneticField | number | 32 | Distance in pixels where the effect activates |
| lerpFactor | number | 0.2 | Smoothness of the animation (0-1, lower = smoother) |
#### Returns
| Property | Type | Description |
|----------|------|-------------|
| ref | RefObject | Attach this to your target element |
| style | CSSProperties | Spread this onto your element's style |
| position | {x: number, y: number} | Raw transform values (optional) |
$3
A responsive helper that detects mobile screens.
#### Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| breakpoint | number | 768 | Screen width threshold in pixels |
#### Returns
| Type | Description |
|------|-------------|
| boolean \| undefined | true if screen âĪ breakpoint, undefined during SSR |
---
ðĻ Use Cases & Examples
$3
`jsx
function MagneticCTA() {
const { ref, style } = useAttract({ strength: 60 });
return (
ref={ref}
style={{
...style,
padding: '16px 32px',
fontSize: '18px',
fontWeight: 'bold',
background: 'linear-gradient(45deg, #f09433 0%, #e6683c 25%, #dc2743 50%, #cc2366 75%, #bc1888 100%)',
color: 'white',
border: 'none',
borderRadius: '50px',
cursor: 'pointer',
}}
>
Get Started ð
);
}
`
$3
`jsx
function ProductCard({ product }) {
const { ref, style } = useAttract({
strength: 30,
magneticField: 40
});
return (
ref={ref}
style={{
...style,
width: '300px',
padding: '20px',
background: 'white',
borderRadius: '12px',
boxShadow: '0 4px 6px rgba(0,0,0,0.1)',
cursor: 'pointer',
}}
>
{product.name}
${product.price}
$3
`jsx
function FloatingIcon({ icon, label }) {
const { ref, style } = useAttract({
strength: 25,
lerpFactor: 0.1
});
return (
ref={ref}
style={{
...style,
width: '80px',
height: '80px',
background: 'rgba(255,255,255,0.1)',
borderRadius: '50%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '32px',
cursor: 'pointer',
backdropFilter: 'blur(10px)',
}}
title={label}
>
{icon}
---
ð§ Framework Compatibility
| Framework | Support | Notes |
|-----------|---------|-------|
| React | â
18.x, 19.x+ | Full support |
| Next.js | â
14+ | Use 'use client' directive |
| Vite | â
All versions | Works out of the box |
| Create React App | â
All versions | Works out of the box |
| Remix | â
All versions | Client-side only |
| Gatsby | â
All versions | Client-side only |
---
ðŊ Performance Tips
- Use enabled: false to disable the effect on mobile devices
- Adjust lerpFactor for smoother animations (lower values = smoother)
- Consider using useMobile() to conditionally apply effects
- The hook automatically cleans up event listeners on unmount
`jsx
const isMobile = useMobile(768);
const { ref, style } = useAttract({
enabled: !isMobile, // Disable on mobile
strength: isMobile ? 0 : 50
});
`
---
ðĪ Contributing
We welcome contributions! Here's how you can help:
1. Fork the repository
2. Create a feature branch (git checkout -b feature/amazing-feature)
3. Commit your changes (git commit -m 'Add amazing feature')
4. Push to the branch (git push origin feature/amazing-feature)
5. Open a Pull Request
$3
`bash
git clone https://github.com/yourusername/use-attract.git
cd use-attract
npm install
npm run dev
``