loading-states
Handle loading states in the portal app using Flask loaders. Use when adding loading indicators to buttons, cards, pages, or any async operations.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install legacy3-wowlab-loading-states
Repository
Skill path: .claude/skills/loading-states
Handle loading states in the portal app using Flask loaders. Use when adding loading indicators to buttons, cards, pages, or any async operations.
Open repositoryBest for
Primary workflow: Ship Full Stack.
Technical facets: Full Stack.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: legacy3.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install loading-states into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/legacy3/wowlab before adding loading-states to shared team environments
- Use loading-states for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: loading-states
description: Handle loading states in the portal app using Flask loaders. Use when adding loading indicators to buttons, cards, pages, or any async operations.
---
# Loading States in Portal
The portal uses custom Flask loader components for all loading states. Never use `Loader2` from lucide-react or CSS `animate-spin`.
## Components
Import from `@/components/ui/loader` or `@/components/ui`:
| Component | Use Case |
| --------------- | ----------------------------------------------------------- |
| `Loader` | Centered loading for cards, panels |
| `InlineLoader` | Inline loading in buttons, text, badges |
| `CardLoader` | Full card loading with optional message |
| `PageLoader` | Full page loading (rarely needed) |
| `OverlayLoader` | Overlay with blur for blocking interactions |
| `Button` | Has built-in `loading` prop (from `@/components/ui/button`) |
## Variants
Both `Loader` and `InlineLoader` support variants:
| Variant | Use When |
| ------------------- | ---------------------------------------- |
| `loading` (default) | Fetching data, waiting for response |
| `processing` | Running computations, simulations, tests |
| `idle` | Ready state with subtle animation |
## Button Loading States
### Simple Button with Loading (recommended)
The `Button` component has a built-in `loading` prop:
```tsx
import { Button } from "@/components/ui/button";
<Button loading={isLoading} onClick={handleSave}>
Save Changes
</Button>;
```
With loading text and loader placement:
```tsx
<Button loading={isLoading} loadingText="Saving..." loaderPlacement="end">
Save
</Button>
```
Button loading props:
- `loading` - shows the loader and disables the button
- `loadingText` - text to show while loading (if omitted, children are hidden but preserved for width)
- `loaderPlacement` - "start" (default) or "end" for position when using loadingText
### Manual Control with InlineLoader
For cases where you need manual control (e.g., different icons, processing variant):
```tsx
import { InlineLoader } from "@/components/ui/loader";
import { Button } from "@/components/ui/button";
import { Save } from "lucide-react";
<Button disabled={isLoading}>
{isLoading ? <InlineLoader /> : <Save />}
Save
</Button>;
```
### Processing Button (simulations, tests)
```tsx
import { InlineLoader } from "@/components/ui/loader";
<Button disabled={isRunning}>
{isRunning ? <InlineLoader variant="processing" /> : <Play />}
Run Simulation
</Button>;
```
## Card/Panel Loading
### Inside a Card
```tsx
import { Loader } from "@/components/ui/loader";
{
loading ? (
<styled.div
display="flex"
alignItems="center"
justifyContent="center"
py="8"
>
<Loader size="sm" />
</styled.div>
) : (
<CardContent>...</CardContent>
);
}
```
### CardLoader with Message
```tsx
import { CardLoader } from "@/components/ui/loader";
{
loading && <CardLoader message="Loading data ..." />;
}
```
### Inline with Text
```tsx
import { InlineLoader } from "@/components/ui/loader";
<styled.div display="flex" alignItems="center" justifyContent="center" py="8">
<InlineLoader />
<styled.span ml="2" textStyle="sm" color="fg.muted">
Loading coverage data...
</styled.span>
</styled.div>;
```
## Status Indicators
### Active Job/Process
```tsx
import { InlineLoader } from "@/components/ui/loader";
{
job.status === "running" ? (
<InlineLoader variant="processing" />
) : (
<CheckIcon />
);
}
```
### In Links (name resolution)
```tsx
import { InlineLoader } from "@/components/ui/loader";
{
isLoading && <InlineLoader css={{ opacity: 0.5 }} />;
}
```
## Sizes
`Loader` sizes (Panda CSS spacing tokens):
- `xs` - 16px (4 spacing units) - used by `InlineLoader`
- `sm` - 24px (6 spacing units)
- `md` - 48px (12 spacing units) - default
- `lg` - 64px (16 spacing units)
- `xl` - 96px (24 spacing units)
`InlineLoader` is just `Loader` with `size="xs"` (16px).
## Page Loading (loading.tsx)
For route-level loading, keep using Skeleton components in `loading.tsx` files - they provide structural hints. Don't use Loader for page-level loading.
```tsx
// app/feature/loading.tsx
import { FeatureSkeleton } from "@/components/feature";
export default function FeatureLoading() {
return <FeatureSkeleton />;
}
```
## Decision Guide
1. **Button loading** → `Button` with `loading` prop (preferred) or `InlineLoader` for manual control
2. **Running simulation/test** → `InlineLoader variant="processing"`
3. **Card/panel data loading** → `Loader size="sm"` or `CardLoader`
4. **Active job indicator** → `InlineLoader variant="processing"`
5. **Inline status** → `InlineLoader`
6. **Page loading** → Skeleton components (not Loader)