# StatusMorph

> A 1em SVG status icon that morphs between idle, loading, success, and error, closing its spinning ring into a drawn check or cross with a portalled live region announcing each state.

- Package: `fancy-ui-vue` (Vue 3.5+ + Tailwind CSS v4)
- Category: Feedback
- Tags: status, icon, loading, success, error, morph, micro-interaction
- Types: `StatusMorphProps`, `StatusMorphState`
- Docs: https://fancy-ui.rama.app/docs/components/status-morph
- Source: https://github.com/RamaHerbin/fancy-ui/tree/main/vue/src/components/status-morph

## Import

```vue
<script setup lang="ts">
import { StatusMorph } 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 |
| --- | --- | --- | --- |
| `v-model:state` (Svelte `state`) | `"idle" \| "loading" \| "success" \| "error"` | `"idle"` | Current state, two-way bound. The component only ever writes it back to "idle" itself, when resetAfter fires — every other write is the caller's, and is always honoured |
| `resetAfter` | `number` | `1800` | Milliseconds until an automatic reset to "idle" after "success" or "error". 0 disables the timer entirely (manual reset only) |
| `labels` | `{ loading?: string; success?: string; error?: string }` | `{ loading: "Loading", success: "Done", error: "Failed" }` | Live-region text per state; unset keys fall back to the defaults |
| `tone` | `"current" \| "semantic"` | `"current"` | "current" paints every glyph in currentColor; "semantic" reads the shared --ft-status-running/-done/-error vocabulary instead |
| `haptic` | `boolean` | `false` | Best-effort tactile feedback (the success/error haptic patterns) on entering those states; silently a no-op wherever the Vibration API is unsupported or refused |
| `class` | `string` | — | Additional CSS classes |
| `ref` | `HTMLSpanElement \| null` | `null` | Bindable reference to the root element |

## Slots

| Slot | Description |
| --- | --- |
| `#idle` (Svelte `idle`) | Custom idle content, rendered in the same calc(1em + 1px) footprint instead of the default transparent scaffold, so swapping to it never shifts layout |

## 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/status-morph.md.
