# Magnet

> Elements ease toward the cursor on a real spring, with tilt, scale, axis locking and a movement cap. Only the nearest magnet reacts when several overlap.

Move the cursor near the element and it leans toward it on a spring, with a smooth pull that fades in at the edge of its range. It can tilt in 3D, grow a little, stay on one axis or stop at a maximum offset. When several magnets overlap, only the nearest one moves, unless you turn off `exclusive` so a group (like dock icons) leans together. Switch scenes and presets in the panel.

<demo-magnet>



</demo-magnet>

## Installation

```bash
npx shadcn-vue@latest add "https://nxui.geoql.in/r/magnet.json"
```

## Usage

```vue
<script setup lang="ts">
  import Magnet from '~/components/ui/magnet/Magnet.vue';
</script>

<template>
  <Magnet
    :padding="100"
    :magnet-strength="2"
    :tilt="6"
    :max-offset="10"
    :spring="{ stiffness: 170, damping: 16 }"
  >
    <button
      type="button"
      class="h-11 rounded-xl bg-primary px-5 text-primary-foreground"
    >
      Get started
    </button>
  </Magnet>
</template>
```

## Props

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        padding
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        100
      </code>
    </td>
    
    <td>
      Distance in px around the element where the cursor starts to pull it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        magnet-strength
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        2
      </code>
    </td>
    
    <td>
      The cursor offset is divided by this value, so 1 follows the cursor and higher values move less.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        exclusive
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      When several magnets are in range, only the nearest exclusive one is pulled. Turn off for groups.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        axis
      </code>
    </td>
    
    <td>
      <code>
        'both' | 'x' | 'y'
      </code>
    </td>
    
    <td>
      <code>
        'both'
      </code>
    </td>
    
    <td>
      Limits the movement to one axis.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        max-offset
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        -
      </code>
    </td>
    
    <td>
      Caps how far the element can move from its resting place, in px.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tilt
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Maximum 3D tilt toward the cursor, in degrees.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scale
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Scale of the element while the cursor pulls it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        spring
      </code>
    </td>
    
    <td>
      <code>
        { stiffness?: number; damping?: number; mass?: number }
      </code>
    </td>
    
    <td>
      <code>
        { stiffness: 170, damping: 16, mass: 1 }
      </code>
    </td>
    
    <td>
      Spring that drives the movement. Higher stiffness reacts faster, lower damping overshoots and wobbles.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        disabled
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Turns the effect off and lets the element spring back to rest.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Classes for the outer wrapper, which stays in place.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        inner-class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Classes for the inner element that moves.
    </td>
  </tr>
</tbody>
</table>

## Events

<table>
<thead>
  <tr>
    <th>
      Event
    </th>
    
    <th>
      Payload
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        active-change
      </code>
    </td>
    
    <td>
      <code>
        active: boolean
      </code>
    </td>
    
    <td>
      Fires when the cursor enters or leaves the magnetic area. The wrapper also gets a <code>
        data-magnet-active
      </code>
      
       attribute.
    </td>
  </tr>
</tbody>
</table>

## Slots

<table>
<thead>
  <tr>
    <th>
      Slot
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        default
      </code>
    </td>
    
    <td>
      The content that moves toward the cursor.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The wrapper adds no roles or focus stops; your slotted button or link keeps its own semantics and focus ring.
- Touch pointers are ignored, so taps never shift a target out from under a finger.
- With `prefers-reduced-motion: reduce` the element stays still.
- All magnets share one pointer listener, and each spring loop stops once it is at rest.
- Ported from [React Bits](https://reactbits.dev/animations/magnet) by David Haz.
