# Reference

Every attribute and every token in one place, generated from the same manifest entry the TypeScript types are.

Two attributes and 7 tokens. That is the whole surface. Anything that
typechecks is listed here, and anything listed here has a rule behind it.

## Attributes

| Attribute | Accepts | Required | What it is for | Example |
| --- | --- | --- | --- | --- |
| `data-motion` | One preset id, or two composed ids separated by a space. | yes | The whole API. Names the preset that animates the element. The other half of the match is the state attribute the host already writes, so this is the only thing you add. | `<Dialog.Content data-motion="scale-fade" />` |
| `data-motion-state` | "open" or "closed". | no | The escape hatch for a host that publishes no open and closed pair of its own. Write it from the app and the transition path matches on it exactly as it matches Base UI ending styles. Base UI scroll area needs it, and so does any element you keep mounted and hide yourself. | `<ScrollArea.Scrollbar data-motion="fade" data-motion-state={shown ? "open" : "closed"} />` |

## Tokens

Every token is declared on `:root` inside `@layer easeful`. Override one in your own unlayered
CSS and it wins without `!important`, which restyles every preset at once rather than one of
them.

| Token | Default | What it controls |
| --- | --- | --- |
| `--motion-duration` | `200ms` | Enter duration. |
| `--motion-duration-exit` | `150ms` | Exit duration. Faster than enter feels better. |
| `--motion-ease` | `cubic-bezier(0.32, 0.72, 0, 1)` | Enter easing, decelerating. |
| `--motion-ease-exit` | `cubic-bezier(0.4, 0, 1, 1)` | Exit easing, accelerating. |
| `--motion-distance` | `8px` | Small travel distance for slide presets. |
| `--motion-scale` | `0.96` | Scale factor for scale-in presets. |
| `--motion-origin` | `center` | Default transform-origin. |

## Composition

Two presets on one element, separated by a space. The manifest declares which pairs compose and
which fight over the same property, and the types accept a pair, so
`data-motion="fade nonsense"` fails to compile.

```tsx
<Dialog.Content data-motion="fade slide-up" />
```

## Writing direction

No preset moves along the inline axis today. `slide-up` is vertical, so nothing in the current
vocabulary changes meaning in a right-to-left document.

The decision, recorded before a `slide-start` or `slide-end` preset exists rather than after
it ships: an inline-axis preset follows writing direction. It will set an inline-axis variable
rather than `--motion-from-x`, and one rule will flip its sign under `:dir(rtl)`. Physical
`slide-left` and `slide-right` names stay out of the vocabulary, because a name that means
"toward the trigger" in one document and "away from it" in another is the ambiguity a closed
vocabulary exists to prevent.

The rule itself ships with the first preset that needs it, and not before. A custom property
nothing reads is the same broken promise as an attribute that typechecks and matches nothing.
