Fetch + Loading State

Loading, success, and error states for async data fetching.

Live Demo

Loading users...
NameEmailRole

Source

HTML + JavaScript
<div data-component="fetch-users">
    <button data-action="fetchData">Fetch Users</button>

    <div data-show="loading">Loading...</div>

    <div data-show="error">
        <span data-bind="error"></span>
        <button data-action="fetchData">Retry</button>
    </div>

    <!-- data-render removes the table from DOM when empty -->
    <div data-render="users.length > 0">
        <table>
            <tbody data-list="users">
                <template>
                    <tr><td data-bind="name"></td><td data-bind="email"></td></tr>
                </template>
            </tbody>
        </table>
    </div>
</div>

<script>
wildflower.component('fetch-users', {
    state: { users: [], loading: false, error: '' },
    fetchData() {
        this.loading = true;
        this.error = '';
        // Replace setTimeout with: fetch('/api/users').then(...)
        setTimeout(() => {
            this.users = [
                { name: 'Alice', email: 'alice@example.com', role: 'Admin' },
                { name: 'Bob', email: 'bob@example.com', role: 'Editor' }
            ];
            this.loading = false;
        }, 1000);
    },
    fetchError() {
        this.loading = true;
        this.error = '';
        setTimeout(() => {
            this.loading = false;
            this.error = 'Network error: could not reach API.';
        }, 1000);
    }
});
</script>

Key Points

  • Three exclusive states managed with data-show: loading, error, and data
  • data-render="users.length > 0" removes the table from DOM entirely when there's no data, cleaner than data-show for heavy content
  • The Retry button just calls the same fetch method. This pattern works for fetch(), XMLHttpRequest, or any Promise
  • Replace the setTimeout with a real fetch() call. The state management pattern stays identical