# <motion-ticker>

Horizontal auto-scrolling ticker / marquee. Duplicates children to create a
seamless infinite loop. Supports pause-on-hover, keyboard pause (Space/Enter),
direction control, and an optional sine-wave vertical oscillation effect.

**Use it for:** a looping strip of short items, such as logos, tags or
news headlines, that moves sideways across the page on its own.

**Avoid it for:** links, buttons and other controls: only the original
items can be clicked or focused, not the copies, and the ticker keeps
moving while one of them has focus. Also avoid it for content people must
read in full. For items that people move through themselves, use
`motion-slider`.

**Accessibility:** the ticker is focusable (`tabindex="0"`) and has
`role="region"` with the `aria-label` "Scrolling ticker. Press Space to
pause.", which replaces any `aria-label` you set in the HTML. Hover (with
`pause-on-hover`) and focus slow it to a stop. When the ticker itself has
focus, Space or Enter pauses it until one of them is pressed again. Key
presses on items inside it are left alone. Every copy of the items is
`aria-hidden` and `inert`, so screen readers read each item once and Tab
reaches only the original items.

**Reduced motion:** the ticker is not built and does not move. The items
stay in normal flow, with no copies and no `gap`. It gets no `tabindex`,
role or label, because there is nothing to pause.

**Common mistakes:** putting bare text directly inside: only child elements
become items, so wrap each item in an element such as `<span>`. With
`wave`, the ticker does not clip its content, so the items can show past
its edges and make the page scroll sideways; put it in a parent with
`overflow-x: clip`.

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

## Install

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

Or without a build step:

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

## Example

```html
<motion-ticker speed="80" gap="48" direction="right" wave wave-amplitude="12" wave-length="200">
  <span>Item one</span>
  <span>Item two</span>
  <span>Item three</span>
</motion-ticker>
```

## Attributes

| Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `speed` | `number` | `60` | Scroll speed in pixels per second. |
| `gap` | `number` | `32` | Gap between items in pixels. |
| `direction` | `'left'\|'right'` | `'left'` | Scroll direction. |
| `pause-on-hover` | `boolean` | `true` | Pause on mouse enter / focus. Set `"false"` to keep scrolling. Read once on connect. |
| `wave` | `boolean` | `false` | Enable sine-wave vertical oscillation. Read once on connect. |
| `wave-amplitude` | `number` | `10` | Wave amplitude in pixels. Read once on connect. |
| `wave-length` | `number` | `300` | Wave length in pixels. Read once on connect. |

## 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 |
| --- | --- |
| `pause()` | Holds the ticker. A pause from your code also ends any hover hold, so leaving does not lift it. |
| `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. |
| `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) | Items to scroll. Each direct child is duplicated to fill the container. `speed`, `gap` and `direction` are live: changing them restarts the marquee. The remaining attributes are read once while the marquee is built. |
