List Enter/Exit

Animate items as they enter and leave a data-list.

Live Demo

Source

HTML + JavaScript + CSS
<div data-component="animated-list">
    <button data-action="addItem">+ Add</button>
    <button data-action="removeFirst">Remove First</button>

    <div data-list="items" data-key="id">
        <template>
            <div class="list-item" style="animation: list-item-in 0.3s ease;">
                <span data-bind="label"></span>
                <button data-action="removeItem">&times;</button>
            </div>
        </template>
    </div>
</div>

<style>
@keyframes list-item-in {
    from { opacity: 0; transform: translateX(-20px); }
    to { opacity: 1; transform: translateX(0); }
}
@keyframes list-item-out {
    from { opacity: 1; transform: translateX(0); max-height: 50px; }
    to { opacity: 0; transform: translateX(20px); max-height: 0; }
}
</style>

<script>
wildflower.component('animated-list', {
    state: {
        nextId: 4,
        items: [
            { id: 1, label: 'Item 1' },
            { id: 2, label: 'Item 2' },
            { id: 3, label: 'Item 3' }
        ]
    },
    addItem() {
        this.items.push({ id: this.nextId, label: 'Item ' + this.nextId });
        this.nextId++;
    },
    _animateOut(el, callback) {
        el.style.animation = 'list-item-out 0.25s ease forwards';
        el.style.overflow = 'hidden';
        el.addEventListener('animationend', callback, { once: true });
    },
    removeFirst() {
        const el = this.find('[data-list] .list-item');
        if (!el) return;
        this._animateOut(el, () => this.items.shift());
    },
    removeItem(e, el, { index }) {
        const row = el.closest('.list-item');
        if (!row) return;
        this._animateOut(row, () => this.items.splice(index, 1));
    }
});
</script>

Key Points

  • Enter: CSS animation on the template's root element runs automatically when items are added to the DOM
  • Exit: Apply an exit animation, then remove the item in the animationend callback
  • data-key="id" ensures correct item identity, preventing stale animations on reorder
  • The _animateOut helper keeps exit logic reusable across remove methods