<!-- Source: https://motion.svelte.page/examples/html-content -->

# HTML Content

> Animate HTML content with smooth enter and exit transitions using Svelte Motion. Demonstrates AnimatePresence with dynamic HTML elements.

**Source:** [https://motion.svelte.page/examples/html-content](https://motion.svelte.page/examples/html-content)

**Markdown mirror:** [https://motion.svelte.page/examples/html-content.md](https://motion.svelte.page/examples/html-content.md)

---

This mirror preserves the prose, implementation notes, and runnable Svelte source behind the live example page.

## FIG-001: animating html content.

`animate(from, to, options)` drives any imperative value over time. `onUpdate` hands you the latest interpolated number — round it and write it into `$state` to render rich HTML on every frame.

**Metadata:** tag: `ANIMATE` | pattern: `animate() → state`

### Notes

- `animate(0, 100, &#123; duration: 5 &#125;)` returns controls that walk the value imperatively. Unlike `motion.*` props which animate styles, this lets you drive any JS value — text, canvas, business logic.
- The `onUpdate` callback fires every frame with the interpolated value. Rounding it before storing turns a continuous tween into an integer counter — the same trick works for currency, percentages, or any formatted text.
- `controls.stop()` in the `onMount` cleanup halts the animation if the component unmounts mid-tween. Important — without it the closure keeps writing into `$state` after the component is gone.

### Source

#### Default.svelte

Source file: [src/lib/examples/html-content/demos/Default.svelte](https://github.com/humanspeak/svelte-motion/blob/main/docs/src/lib/examples/html-content/demos/Default.svelte)

```svelte
<script lang="ts">
    import { animate, motion, styleString } from '@humanspeak/svelte-motion'
    import { onMount } from 'svelte'

    // `animate(from, to, options)` drives any imperative value over time.
    // The `onUpdate` callback hands you the latest interpolated value —
    // round it, format it, and stuff it into `$state` to render rich HTML
    // content (here, a giant counter) on each frame.
    let count = $state(0)

    onMount(() => {
        const controls = animate(0, 100, {
            duration: 5,
            onUpdate: (latest: number) => {
                count = Math.round(latest)
            }
        }) as unknown as { stop: () => void }
        return () => controls.stop()
    })
</script>

<!-- dk-strip: docs-kit positioning shell — stripped from the published code. -->
<div class="dk-demo-shell">
    <div class="strip">
        <div class="strip-head">
            <span class="micro">// html content</span>
            <span class="micro counter">{String(count).padStart(3, '0')} / 100</span>
        </div>

        <div class="stage">
            <motion.pre
                style={styleString(() => ({
                    margin: 0,
                    fontFamily: 'var(--brut-mono, monospace)',
                    fontSize: '64px',
                    fontWeight: 700,
                    lineHeight: 1,
                    fontVariantNumeric: 'tabular-nums',
                    color: 'var(--brut-accent, #247768)'
                }))}>{count}</motion.pre
            >
        </div>

        <div class="strip-foot">
            <span class="micro">source: animate() onUpdate</span>
            <span class="micro">0 → 100 / 5s</span>
        </div>
    </div>
</div>

<style>
    .dk-demo-shell {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 1.5rem;
        min-height: 240px;
    }

    .strip {
        width: 100%;
        max-width: 420px;
        display: flex;
        flex-direction: column;
        gap: 0.75rem;
    }

    .micro {
        font-family: var(--brut-mono, monospace);
        font-size: 0.6875rem;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        color: var(--brut-ink-3, #9a9a9a);
    }

    .counter {
        color: var(--brut-accent, #247768);
        font-variant-numeric: tabular-nums;
    }

    .strip-head,
    .strip-foot {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
        border-bottom: 1px dashed var(--brut-rule-2, #bbc4c0);
        padding-bottom: 0.5rem;
    }

    .strip-foot {
        border-bottom: none;
        border-top: 1px dashed var(--brut-rule-2, #bbc4c0);
        padding-top: 0.75rem;
        padding-bottom: 0;
    }

    .stage {
        height: 7rem;
        display: flex;
        align-items: center;
        justify-content: center;
    }
</style>
```
