Cossack provides built-in support for handling asynchronous operations, allowing you to easily show spinners or skeleton screens while data is being fetched or actions are processing.
File-based Loading Convention (loading.ts)
You can create a loading.ts (or loading.tsx) file in any route directory. Cossack will automatically render this component instantly when a user navigates to that route, while the main Page component is being fetched and its init() method is running.
This is the recommended way to implement global page transitions and high-fidelity skeleton screens.
Example
Directory structure:
src/pages/dashboard/ ├── index.ts <-- Dashboard Page └── loading.ts <-- Dashboard Skeleton
loading.ts:
import { Cossack } from '@cossackframework/core'; import { html } from '@cossackframework/renderer'; export default class DashboardSkeleton extends Cossack { render() { return html`<div class="skeleton">Loading dashboard...</div>`; } }
Initialization Loading (init / get)
When a component is being initialized (via init() or get() methods), Cossack automatically sets this.loading.init to 1.
The loadingTemplate() Convention
If you define a loadingTemplate() method in your component, Cossack will automatically render it while this.loading.init is true. This is useful for component-level loading states or when triggering a refresh.
import { Cossack, Page } from '@cossackframework/core'; import { html } from '@cossackframework/renderer'; @Page() export default class UserProfile extends Cossack { async init() { this.user = await fetchUser(); // Takes 1s } loadingTemplate() { return html` <div class="skeleton-profile"> <div class="skeleton-avatar"></div> <div class="skeleton-line"></div> </div> `; } render() { return html`<h1>Welcome, ${this.user.name}</h1>`; } }
Action Loading (@Server)
When a method decorated with @Server is called on the client, Cossack tracks its progress using the method name in the this.loading object.
async save() { await this.performSave(); } render() { return html` <button @click=${this.save} ?disabled=${this.loading.save}> ${this.loading.save ? 'Saving...' : 'Save Changes'} </button> `; }
How it Works
- File Convention: The Vite plugin discovers
loading.tsfiles and registers them. During navigation, the client router swaps the current page with the nearest matching loading component before starting the network request. - Automatic Tracking: The
Cossackbase class wrapsinit()andget()calls. It incrementsthis.loading.initbefore the call and decrements it after. - SSR Behavior: During Server-Side Rendering, Cossack waits for
init()to complete before sending the final HTML. Therefore, the loading state is typically only visible during client-side interactions.