code-showcase-react-ui-patterns
/code-showcase-react-ui-patterns
Modern React UI patterns for loading states, error handling, and data fetching. Use when building UI components, handling async data, or managing UI states.
- Author
- FrancoStino ↗
- Repository
- opencode-skills-collection ↗
- Licence
- MIT
- Last repository change
- 26.10.2026
Assessment and security
- Files in this package
- 1
- Scripts
- 0
- HTML comments
- 0
- URLs in SKILL.md
- 2
No signals detected. Repository changed on 26.10.2026, without references to retired models or APIs.
MIT, open: use and modify while retaining author attribution.
What it does and when to use it
Modern React UI patterns for loading states, error handling, and data fetching. Use when building UI components, handling async data, or managing UI states.
Original author description
Modern React UI patterns for loading states, error handling, and data fetching. Use when building UI components, handling async data, or managing UI states.
How it works
- When to Use
- Core Principles
- Loading State Patterns
- Error Handling Patterns
- Button State Patterns
- Empty States
- Form Submission Pattern
- Anti-Patterns
- Checklist
- Integration with Other Skills
SKILL.md preview
---
name: code-showcase-react-ui-patterns
description: Modern React UI patterns for loading states, error handling, and data fetching. Use when building UI components, handling async data, or managing UI states.
risk: critical
source: https://github.com/ChrisWiles/claude-code-showcase/tree/main/.claude/skills/react-ui-patterns
source_repo: ChrisWiles/claude-code-showcase
source_type: community
date_added: 2026-07-01
license: MIT
license_source: https://github.com/ChrisWiles/claude-code-showcase/blob/main/LICENSE
---
# React UI Patterns
## When to Use
Use this skill when you need modern React UI patterns for loading states, error handling, and data fetching. Use when building UI components, handling async data, or managing UI states.
## Core Principles
1. **Never show stale UI** - Loading spinners only when actually loading
2. **Always surface errors** - Users must know when something fails
3. **Optimistic updates** - Make the UI feel instant
4. **Progressive disclosure** - Show content as it becomes available
5. **Graceful degradation** - Partial data is better than no data
## Loading State Patterns
### The Golden Rule
**Show loading indicator ONLY when there's no data to display.**
```typescript
// CORRECT - Only show loading when no data exists
const { data, loading, error } = useGetItemsQuery();
if (error) return <ErrorState error={error} onRetry={refetch} />;
if (loading && !data) return <LoadingState />;
if (!data?.items.length) return <EmptyState />;
return <ItemList items={data.items} />;
```
```typescript
// WRONG - Shows spinner even when we have cached data
if (loading) return <LoadingState />; // Flashes on refetch!
```
### Loading State Decision Tree
```
Is there an error?
→ Yes: Show error state with retry option
→ No: Continue
Is it loading AND we have no data?
→ Yes: Show loading indicator (spinner/skeleton)
→ No: Continue
Do we have data?
→ Yes, with items: Show the data
→ Yes, but empty: Show empty state
→ No: Show loading (fallback)
```
### Skeleton vs Spinner
| Use Skeleton When | Use Spinner When |
|-------------------|------------------|
| Known content shape | Unknown content shape |
| List/card layouts | Modal actions |
| Initial page load | Button submissions |
| Content placeholders | Inline operations |
## Error Handling Patterns
### The Error Handling Hierarchy
```
1. Inline error (field-level) → Form validation errors
2. Toast notification → Recoverable errors, user can retry
3. Error banner → Page-level errors, data still partially usable
4. Full error screen → Unrecoverable, needs user action
```
### Always Show Errors
**CRITICAL: Never swallow errors silently.**
```typescript
// CORRECT - Error always surfaced to user
const [createItem, { loading }] = useCreateItemMutation({
onCompleted: () => {
toast.success({ title: 'Item created' });
},
onError: (error) => {
console.error('createItem failed:', error);
toast.error({ title: 'Failed to create item' });
},
});
// WRONG - Error silently caught, user has no idea
const [createItem] = useCreateItemMutation({
onError: (error) => {
console.error(error); // User sees nothing!
},
});
```
### Error State Component Pattern
```typescript
interface ErrorStateProps {
error: Error;
onRetry?: () => void;
title?: string;
}
const ErrorState = ({ error, onRetry, title }: ErrorStateProps) => (
<div className="error-state">
<Icon name="exclamation-circle" />
<h3>{title ?? 'Something went wrong'}</h3>
<p>{error.message}</p>
{onRetry && (
<Button onClick={onRetry}>Try Again</Button>
)}
</div>
);
```
## Button State Patterns
### Button Loading State
```tsx
<Button
onClick={handleSubmit}
isLoading={isSubmitting}
disabled={!isValid || isSubmitting}
>
Submit
</Button>
```
### Disable During Operations
**CRITICAL: Always disable triggers during async operations.**
```tsx
// CORRECT - Button disabled while loading
<Button
disabled={isSubmitting}
isLoading={isSubmitting}
onClick={handleSubmit}
>
Submit
</Button>
// WRONG - User can tap multiple times
<Button onClick={handleSubmit}>
{isSubmitting ? 'Submitting...' : 'Submit'}
</Button>
```
## Empty States
### Empty State Requirements
Every list/collection MUST have an empty state:
```tsx
// WRONG - No empty state
return <FlatList data={items} />;
// CORRECT - Explicit empty state
return (
<FlatList
data={items}
ListEmptyComponent={<EmptyState />}
/>
);
```
### Contextual Empty States
```tsx
// Search with no results
<EmptyState
icon="search"
title="No results found"
description="Try different search terms"
/>
// List with no items yet
<EmptyState
icon="plus-circle"
title="No items yet"
description="Create your first item"
action={{ label: 'Create Item', onClick: handleCreate }}
/>
```
## Form Submission Pattern
```tsx
const MyForm = () => {
const [submit, { loading }] = useSubmitMutation({
onCompleted: handleSuccess,
onError: handleError,
});
const handleSubmit = async () => {
if (!isValid) {
toast.error({ title: 'Please fix errors' });
return;
}
await submit({ variables: { input: values } });
};
return (
<form>
<Input
value={values.name}
onChange={handleChange('name')}
error={touched.name ? errors.name : undefined}
/>
<Button
type="submit"
onClick={handleSubmit}
disabled={!isValid || loading}
isLoading={loading}
>
Submit
</Button>
</form>
);
};
```
## Anti-Patterns
### Loading States
```typescript
// WRONG - Spinner when data exists (causes flash)
if (loading) return <Spinner />;
// CORRECT - Only show loading without data
if (loading && !data) return <Spinner />;
```
### Error Handling
```typescript
// WRONG - Error swallowed
try {
await mutation();
} catch (e) {
console.log(e); // User has no idea!
}
// CORRECT - Error surfaced
onError: (error) => {
console.error('operation failed:', error);
toast.error({ title: 'Operation failed' });
}
```
### Button States
```typescript
// WRONG - Button not disabled during submission
<Button onClick={submit}>Submit</Button>
// CORRECT - Disabled and shows loading
<Button onClick={submit} disabled={loading} isLoading={loading}>
Submit
</Button>
```
## Checklist
Before completing any UI component:
**UI States:**
- [ ] Error state handled and shown to user
- [ ] Loading state shown only when no data exists
- [ ] Empty state provided for collections
- [ ] Buttons disabled during async operations
- [ ] Buttons show loading indicator when appropriate
**Data & Mutations:**
- [ ] Mutations have onError handler
- [ ] All user actions have feedback (toast/visual)
## Integration with Other Skills
- **graphql-schema**: Use mutation patterns with proper error handling
- **testing-patterns**: Test all UI states (loading, error, empty, success)
- **formik-patterns**: Apply form submission patterns
## Limitations
- Use this skill only when the task clearly matches its upstream source and local project context.
- Verify commands, generated code, dependencies, credentials, and external service behavior before applying changes.
- Do not treat examples as a substitute for environment-specific tests, security review, or user approval for destructive or costly actions.
Versions
| Repository | Score | Licence |
|---|---|---|
| This page · FrancoStino/opencode-skills-collection | 100 | MIT |
| sickn33/agentic-awesome-skills | 100 | MIT |
Database snapshot: 13.11.2026 · package version 888d9012e0ed (SHA-256 digest of the entire package)
Downloads in the last 30 days: 0 · ranking
Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.
Similar skills
- 100react-ui-patterns
Modern React UI patterns for loading states, error handling, and data fetching. Use when building UI components, handling async data, or managing UI states. - 100react-ui-patterns
Modern React UI patterns for loading states, error handling, and data fetching. Use when building UI components, handling async data, or managing UI states. - 100react-ui-patterns
Modern React UI patterns for loading states, error handling, and data fetching. Use when building UI components, handling async data, or managing UI states. - 100react-ui-patterns
Modern React UI patterns for loading states, error handling, and data fetching. Use when building UI components, handling async data, or managing UI states. - 95angular-ui-patterns
Modern Angular UI patterns for loading states, error handling, and data display. Use when building UI components, handling async data, or managing component states. - 95angular-ui-patterns
Modern Angular UI patterns for loading states, error handling, and data display. Use when building UI components, handling async data, or managing component states.