loading-states — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited loading-states (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Make sure no user ever stares at a blank or frozen-looking screen: inventory every place the app waits or can be empty, choose the correct state for each by expected latency, and implement it. The prime directive: the indicator is chosen by how long the wait is and whether the layout is known — not by taste. Deliver an audit table covering every async surface plus the implemented states, never a lone spinner component.
Use for: loading indicators, skeleton screens, progress bars, empty states (first-use, no-results, error-empty, success-empty), "app looks frozen" complaints.
Hand off instead when the real need is:
skills/frontend-design/performance-optimization — always consider that first; the best loading state is noneskills/frontend-design/error-handling-recoveryskills/frontend-design/interaction-physicsfetch(, axios, useQuery/useSWR/createResource, isLoading/isPending/loading flags, Suspense boundaries, and route-level data loaders. List every view/component that waits on data or mutation.Ask the user (one batch, only if not inferable): whether any operations are known to be long-running (uploads, exports, batch jobs), and whether there's a design language for illustrations/empty states. Otherwise state assumptions and proceed — never block an audit on questions the code answers.
| Expected wait | Treatment |
|---|---|
| < 100ms | Nothing — an indicator that flashes in and out is worse than none |
| 100ms – 1s | Subtle inline cue: button spinner/opacity, cursor: wait; no layout change |
| 1s – 10s | Skeleton if the incoming layout is known; spinner if not |
| > 10s | Progress bar — determinate with count/percent if measurable, indeterminate + explanatory text if not |
Fork rules:
Every empty view gets one of four treatments — classify, then apply:
| Type | Trigger | Must include |
|---|---|---|
| First use | User has no data yet | What this area is for + primary CTA to create the first item |
| No results | Search/filter matched nothing | Echo of what was searched + escape hatch ("Clear filters") |
| Error-empty | Load failed | Plain-language failure + Retry action (hand complex recovery to skills/frontend-design/error-handling-recovery) |
| Success-empty | All items done (inbox zero) | Positive confirmation; no CTA needed |
Rule: an empty state without an action is a dead end — only success-empty may omit the CTA.
aria-busy="true" and a polite live region announcing "Loading"; skeletons are aria-hidden="true"; progress bars use role="progressbar" with aria-valuenow/min/max; shimmer stops under prefers-reduced-motion.references/patterns.md — read it when writing the code.Simulate slow network (devtools throttling or an artificial delay) and confirm: no blank frames, no layout shift at content swap, indicators don't flash on fast responses, empty states render with their actions.
Deliver both artifacts:
1. The code — implemented skeleton/spinner/progress/empty-state components and their wiring into each async surface, reusing existing project components and tokens.
2. Loading & Empty State Audit (markdown):
## Async surface inventory
| Surface | Wait class | Current | Correct state | Status |
| Product grid | 1–10s (search API) | blank screen | card skeleton ×8 | implemented |
| Save button | 100ms–1s | none | inline button spinner | implemented |
| CSV export | >10s | spinner | determinate progress + count | implemented |
| Comments | unknown → assume 1s class | layout jump | skeleton, space reserved | implemented |
## Empty state coverage
| View | First use | No results | Error-empty | Success-empty |
| Projects list | ✓ CTA "Create project" | n/a | ✓ Retry | n/a |
| Search page | n/a | ✓ "Clear filters" | ✓ Retry | n/a |
## Assumptions
[Latency estimates you could not verify, flagged for the user]aria-busy, live-region announcement, role="progressbar" values, aria-hidden skeletons, reduced-motion handling all presentHard don'ts: no spinner-for-everything; no invented time estimates shown to users ("about 2 minutes") unless derived from real data; no loading state on operations that complete instantly.
skills/frontend-design/performance-optimization → run first or alongside; optimistic UI removes the need for many loading states, and skeleton space-reservation is shared CLS work.skills/frontend-design/error-handling-recovery ← consumes your error-empty placements and expands them into full recovery flows.skills/frontend-design/interaction-physics → supplies shimmer/spinner motion timing and the reduced-motion baseline.skills/frontend-design/component-architecture → provides the component inventory your skeletons must mirror; add Skeleton/EmptyState as shared components there.references/patterns.md — full implementation gallery: skeleton building blocks and card example, spinner and button-loading CSS, determinate/indeterminate progress bars, all four empty-state markups, and the accessibility blocks. Read it when writing the code.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.