# Loading States Pattern Guide
## FE-COMP-001: Add loading states to all async operations
This document outlines the patterns and best practices for adding loading states to async operations in the Veza frontend.
## Components Available
### 1. LoadingSpinner
Located at `@/components/ui/loading-spinner`
```tsx
import { LoadingSpinner } from '@/components/ui/loading-spinner';
;
```
### 2. Skeleton
Located at `@/components/ui/skeleton`
```tsx
import { Skeleton } from '@/components/ui/skeleton';
;
```
### 3. ButtonLoading
Located at `@/components/ui/button-loading`
```tsx
import { ButtonLoading } from '@/components/ui/button-loading';
Submit
;
```
## Patterns
### Pattern 1: Form Submissions
Always disable the submit button and show a loading indicator during submission:
```tsx
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitting(true);
try {
await submitForm();
} finally {
setIsSubmitting(false);
}
};
;
```
### Pattern 2: Data Fetching with TanStack Query
Use `isLoading` from `useQuery`:
```tsx
const { data, isLoading, error } = useQuery({
queryKey: ['key'],
queryFn: fetchData,
});
if (isLoading) {
return ;
}
```
### Pattern 3: Mutations with TanStack Query
Use `isPending` from `useMutation`:
```tsx
const mutation = useMutation({
mutationFn: updateData,
});
;
```
### Pattern 4: Skeleton Loaders for Lists
Use skeleton loaders while data is loading:
```tsx
if (isLoading) {
return (
{Array.from({ length: 5 }).map((_, i) => (
))}
);
}
```
### Pattern 5: Inline Loading States
For operations that don't block the entire UI:
```tsx
```
## Checklist
When implementing async operations, ensure:
- [ ] Button is disabled during operation
- [ ] Loading indicator is visible (spinner or skeleton)
- [ ] Loading text/state is clear to user
- [ ] Error states are handled
- [ ] Success states provide feedback
- [ ] Form inputs are disabled during submission (if applicable)
- [ ] Navigation is prevented during critical operations
## Examples in Codebase
- `PlaylistForm.tsx` - Form submission with loading state
- `FollowButton.tsx` - Inline loading state
- `AddCollaboratorModal.tsx` - Mutation with loading state
- `NotificationsPage.tsx` - Query with loading state
- `SearchPage.tsx` - Multiple queries with loading states