# TextRoll

> Single-line text that rolls to its new value per grapheme, odometer-style, whenever the value prop changes — while the real, unsplit text stays selectable and readable.

- Package: `fancy-ui-vue` (Vue 3.5+ + Tailwind CSS v4)
- Category: Text & Typography
- Tags: text, animation, roll, counter, micro-interaction
- Types: `TextRollProps`
- Docs: https://fancy-ui.rama.app/docs/components/text-roll
- Source: https://github.com/RamaHerbin/fancy-ui/tree/main/vue/src/components/text-roll

## Import

```vue
<script setup lang="ts">
import { TextRoll } from 'fancy-ui-vue';
</script>
```

Setup (once per project): `npm install fancy-ui-vue`, then put these lines in your main CSS file (the stylesheet imports go right after `@import "tailwindcss";`):

```css
@import "tailwindcss";
@import "fancy-ui-vue/tailwind.css";
@import "fancy-ui-vue/styles.css";
```

Full guide: https://fancy-ui.rama.app/llms.txt

The names below are the ones to write in a Vue template; when one differs from the Svelte name, the Svelte name follows in parentheses. Snippets become named slots (`#default` is the default snippet), a prop the Vue port declares as a model is a `v-model:<name>` (except `ref`, exposed via `defineExpose({ ref })`: put a template ref on the component and read `.ref`) and callbacks are listeners (`onclick` is `@click`). Every component sets `inheritAttrs: false`: `class` is a declared prop, merged where the Svelte component applies it (not always the root element), and only when the props table below lists it; other attributes do not fall through unless the package README lists the component as forwarding native attributes. Divergences: https://github.com/RamaHerbin/fancy-ui/tree/main/vue#divergences-from-the-svelte-api

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` (required) | `string` | — | The text to display; a change after mount triggers a per-grapheme roll to the new value |
| `direction` | `"auto" \| "up" \| "down"` | `"auto"` | Which way the cells travel; "auto" compares the trimmed old and new values as numbers and falls back to "up" for a tie, a non-numeric change, or an empty side |
| `duration` | `number` | `300` | Roll duration in ms, collapsed to 0 under reduced motion |
| `stagger` | `number` | `15` | Per-cell stagger step in ms, compressed to a 200ms total spread |
| `from` | `"first" \| "last" \| "center" \| number` | `"first"` | Stagger origin |
| `tabular` | `boolean` | `false` | font-variant-numeric: tabular-nums on both layers, to keep digit width locked |
| `live` | `"off" \| "polite" \| "assertive"` | `"off"` | Live-region role/aria-live pair on the real text layer; off by default |
| `class` | `string` | — | Additional CSS classes |
| `ref` | `HTMLSpanElement \| null` | `null` | Bindable reference to the root element |

## Example

No Vue example is published for this component yet: start from the import above and the props table. The full examples are Svelte-only, on https://fancy-ui.rama.app/docs/components/text-roll.md.
