# Scroll Float

> Scroll-linked text whose letters float, flip, scatter, blur or wave into place, by letter or by word, in any order and from an accent color.

Scroll Float animates a heading as it scrolls through the view, tied to the scroll position. Letters can stretch up out of a slot, roll in on a drum, assemble from random spots, pull into focus or swell in on a rolling wave. Animate each letter or each word, from below or above, and pick which pieces go first. With `from-color` the pieces arrive in an accent color and settle to the text color. Scroll inside the demo and try the presets in the panel.

<demo-scroll-float>



</demo-scroll-float>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import { useTemplateRef } from 'vue';
  import ScrollFloat from '~/components/ui/scroll-float/ScrollFloat.vue';

  const scroller = useTemplateRef<HTMLElement>('scroller');
</script>

<template>
  <!-- "Scatter" preset inside a scrolling box -->
  <div ref="scroller" class="h-100 overflow-y-auto">
    <div class="px-12 pt-190 pb-130">
      <ScrollFloat
        text="Vue nxui"
        :scroll-container="scroller"
        effect="scatter"
        order="random"
        ease="sine.inOut"
        from-color="#ff6b3d"
        :stagger="0.09"
        :smoothing="0.5"
        :distance="170"
      />
    </div>
  </div>
</template>
```

Leave `scroll-container` out to follow the page scroll. Without `text`, the default slot moves in as one piece. Eases use GSAP names (`power1`–`power4`, `expo`, `sine`, `circ`, `back(n)`, `elastic(a, p)`, `bounce`, `none`, each with `.in`, `.out` or `.inOut`) and scroll positions use ScrollTrigger syntax; both run on built-in code, so GSAP is not needed.

## Props

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

<tbody>
  <tr>
    <td>
      <code>
        text
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Text to animate, split into letters or words. Leave it out to animate the default slot as one piece.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scroll-container
      </code>
    </td>
    
    <td>
      <code>
        HTMLElement | null
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      Element that scrolls. <code>
        undefined
      </code>
      
       uses the page; <code>
        null
      </code>
      
       waits until the element exists.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        effect
      </code>
    </td>
    
    <td>
      <code>
        'float' | 'flip' | 'scatter' | 'blur' | 'wave'
      </code>
    </td>
    
    <td>
      <code>
        'float'
      </code>
    </td>
    
    <td>
      Float stretches pieces up out of a slot, flip rolls them in on a drum, scatter assembles them from random spots, blur pulls them into focus, wave swells them in on a rolling wave.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        split-by
      </code>
    </td>
    
    <td>
      <code>
        'chars' | 'words'
      </code>
    </td>
    
    <td>
      <code>
        'chars'
      </code>
    </td>
    
    <td>
      Animate each letter on its own or each word as one piece.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        direction
      </code>
    </td>
    
    <td>
      <code>
        'up' | 'down'
      </code>
    </td>
    
    <td>
      <code>
        'up'
      </code>
    </td>
    
    <td>
      Whether the pieces come in from below or from above.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        order
      </code>
    </td>
    
    <td>
      <code>
        'start' | 'end' | 'center' | 'edges' | 'random'
      </code>
    </td>
    
    <td>
      <code>
        'start'
      </code>
    </td>
    
    <td>
      Which pieces go first. The random order is fixed, so it looks the same on every visit.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        from-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'currentColor'
      </code>
    </td>
    
    <td>
      Color the pieces start in before they settle to the text color. <code>
        currentColor
      </code>
      
       turns the shift off.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        animation-duration
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Length of each piece's animation, relative to the stagger.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ease
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'back.inOut(2)'
      </code>
    </td>
    
    <td>
      GSAP-style ease for the motion.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        stagger
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.03
      </code>
    </td>
    
    <td>
      Delay between pieces, relative to the duration.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        distance
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        120
      </code>
    </td>
    
    <td>
      How far the pieces travel. <code>
        120
      </code>
      
       is the default reach; <code>
        0
      </code>
      
       keeps them in place.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        stretch
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        2.3
      </code>
    </td>
    
    <td>
      How tall the pieces are stretched while they float or wave in.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        smoothing
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Seconds the animation takes to catch up with the scroll. <code>
        0
      </code>
      
       ties it to the scroll directly.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scroll-start
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'center bottom+=50%'
      </code>
    </td>
    
    <td>
      Scroll position where the animation starts.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scroll-end
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'bottom bottom-=40%'
      </code>
    </td>
    
    <td>
      Scroll position where the animation ends. Clamped so text near the end of the page still finishes.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text-class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes on the text.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes on the heading.
    </td>
  </tr>
</tbody>
</table>

## Slots

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

<tbody>
  <tr>
    <td>
      <code>
        default
      </code>
    </td>
    
    <td>
      Content animated as one piece when <code>
        text
      </code>
      
       is unset.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- When `text` is set, a visually hidden copy carries the full sentence and the split letters are `aria-hidden`.
- With `prefers-reduced-motion: reduce` the text is shown at once in its final place.
- Scroll handling is passive, and the smoothing loop stops as soon as the animation catches up.
- Ported from [React Bits](https://reactbits.dev/text-animations/scroll-float) by David Haz.
