# <motion-font>

Animated variable-font axes. Smoothly interpolates one or more variation
axes (weight, slant, optical size, custom axes…) between `from` and `to`,
triggered by viewport entry, hover, or scroll progress.

Uses `CSS.registerProperty` to enable interpolation of `<number>` custom
properties, then drives `font-variation-settings` from those properties.

**Use it for:** headings, links and labels in a variable font whose weight,
slant or width changes when they scroll into view, on hover or focus, or
with scroll progress.

**Avoid it for:** fonts that are not variable fonts, or that do not have the
axis you set, because nothing changes. To scale or move an element on
hover, use `motion-hover`.

**Accessibility:** the slotted text stays real text, so screen readers read
it as normal. With `trigger="hover"`, focus on a focusable element inside,
such as a link, also starts the change; the element itself does not take
focus. A change in weight or width can change the text width and move the
text around it.

**Reduced motion:** with `trigger="view"` or `trigger="scroll"`, the axes
are set to their `to` values at once and do not follow the scroll. With
`trigger="hover"`, the axes switch between `from` and `to` at once, with no
transition.

**Common mistakes:** changing `axis`, `axes`, `from`, `to` or `trigger`
after the element first renders. The setup reads them once, so set them in
the markup. Setting both `axes` and `axis`: `axes` wins, and `axis`, `from`
and `to` are ignored.

Docs: https://www.motion-components.dev/docs/text/motion-font/

## Install

```js
import 'motion-components/motion-font'
```

Or without a build step:

```html
<script type="module" src="https://cdn.jsdelivr.net/npm/motion-components@1/dist/motion-font.js/+esm"></script>
```

## Example

```html
<motion-font axis="wght" from="300" to="800" trigger="hover">
  Variable font
</motion-font>

<motion-font axes="wght:300:800 slnt:0:-12" trigger="scroll">
  Multi-axis on scroll
</motion-font>
```

## Attributes

| Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `axis` | `string` | `'wght'` | Single-axis tag to animate (e.g. `'wght'`, `'slnt'`, `'opsz'`). Ignored if `axes` is set. |
| `axes` | `string` | `''` | Multi-axis spec: space-separated `axis:from:to` triples. Overrides `axis`/`from`/`to`. |
| `from` | `number` | `300` | Single-axis start value. |
| `to` | `number` | `700` | Single-axis end value. |
| `duration` | `number` | `0.6` | Spring duration of the axis transition, in seconds. |
| `bounce` | `number` | `0` | Spring bounce factor (0 = no overshoot). |
| `delay` | `number` | `0` | Delay before the transition starts, in seconds. |
| `trigger` | `'view' \| 'hover' \| 'scroll'` | `'view'` | Trigger source: `'view'` (when scrolled into view), `'hover'`, or `'scroll'` (progress-mapped). |
| `once` | `boolean` | `true` | When `true` and `trigger="view"`, only animate the first time it enters view. Set `once="false"` to turn it off. Ignored with `loop`. |
| `loop` | `boolean` | `false` | With `trigger="view"`, run from `from` to `to`, hold, back to `from`, wait, then repeat. |
| `hold` | `number` | `1.6` | With `loop`, seconds the axes stay at `to` before they spring back to `from`. |
| `gap` | `number` | `0.5` | With `loop`, seconds the axes stay at `from` before they run to `to` again. |
| `pause-on-hover` | `boolean` | `false` | Pause the loop while the pointer is over the text. |

## Properties

| Property | Type | Description |
| --- | --- | --- |
| `playState` | `'idle' \| 'running' \| 'paused' \| 'finished'` | Current state: `'idle'`, `'running'`, `'paused'` or `'finished'`. |
| `finished` | `Promise<void>` | Resolves when the current run settles. A new run replaces the promise. |

## Methods

| Method | Description |
| --- | --- |
| `replay()` | Runs the axes from `from` to `to` again. Only valid when `trigger="view"`. |
| `play()` | Starts the animation, or resumes it when paused. Resolves once the run settles. Under `prefers-reduced-motion: reduce` the final state is applied immediately without animating. |
| `pause()` | Holds the animation at its current position. No-op unless running. |
| `finish()` | Jumps to the final state and settles. Fires `motion-finish`. |
| `cancel()` | Reverts to the initial state and returns to idle. Fires `motion-cancel`. |

## Events

The `motion-*` events bubble and are composed.

| Event | Description |
| --- | --- |
| `motion-start` | When a run starts. |
| `motion-finish` | When a run finishes, or `finish()` jumps to the end. |
| `motion-cancel` | When `cancel()` stops a run and resets it. |

## Slots

| Slot | Description |
| --- | --- |
| (default) | The text whose font axes will animate. |
