# Edge State Design

> SKILL — Edge State Design

- Skill: `nickgallick/edge-state-design` (Agent Skill)
- Install (CLI): `npx skillmds@latest add nickgallick/edge-state-design`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nickgallick/edge-state-design/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: nickgallick (https://skillmd.com/u/nickgallick)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/nickgallick/edge-state-design

---

# SKILL — Edge State Design

Pixel's edge state knowledge. A design that only works with perfect data is not a design — it's a mockup. Real designs handle every state.

---

## The 8 Edge States

### 1. Empty State
**When**: No data exists yet. First-time user, no results, empty list.

**Rules**:
- Never show a blank screen or just "No data"
- Include an illustration or icon (relevant, not generic)
- Explain what would be here ("No transactions yet")
- Provide a clear action ("Create your first transaction")
- The action should be the primary CTA — large, obvious
- If the emptiness is due to filters, say so ("No results match your filters") with a "Clear filters" action

**Examples**:
- Empty inbox: Illustration + "No messages yet. Start a conversation."
- Empty dashboard: Placeholder cards + "Add your first widget"
- No search results: "No results for '[query]'. Try different keywords."

### 2. Loading State
**When**: Data is being fetched, an action is processing, content is rendering.

**Rules**:
- Use skeleton screens for content that has a known structure (preferred over spinners)
- Use spinners for actions with unknown duration (submit buttons, global loading)
- Match skeleton shapes to the actual content layout
- Never show a blank screen while loading
- Show loading within 100ms if data isn't ready
- For operations > 2 seconds, add a text indicator ("Loading transactions...")
- For operations > 5 seconds, add a progress bar or percentage if possible
- Loading state should not cause layout shift when content arrives

**Skeleton Design**:
- Rounded rectangles matching text lines
- Circle/square for avatars
- Subtle pulse animation (respecting prefers-reduced-motion)
- Same padding and spacing as loaded state

### 3. Error State
**When**: Something went wrong. Network failure, server error, invalid data, timeout.

**Rules**:
- Clear message: What happened (not technical jargon)
- Actionable: What the user can do about it ("Try again", "Contact support")
- Scoped: Error affects only the relevant component, not the entire page
- Recoverable: Retry button that actually works
- Preserved: Don't lose user input on error — preserve form data
- Styled: Use semantic error colors (red/destructive) but don't alarm
- Never show raw error messages, stack traces, or error codes to users

**Error Levels**:
- **Inline**: Field-level validation errors
- **Component**: A single card/widget fails to load
- **Section**: Part of the page is unavailable
- **Page**: The entire page can't be loaded
- **Global**: The application can't connect at all

### 4. Single Item State
**When**: A list, table, or grid has exactly one item.

**Rules**:
- The layout should still look intentional with one item
- Grid: Single item shouldn't stretch full width (maintain card size)
- Table: One row shouldn't look broken
- List: One item should still have proper padding and structure
- May want to prompt for adding more ("Add another")

### 5. Many Items State
**When**: Hundreds or thousands of items.

**Rules**:
- Pagination or infinite scroll (with clear end indicator)
- Virtualized rendering for large lists (mention in spec for Maks)
- Show total count ("Showing 1-25 of 1,432")
- Provide filtering and search to narrow results
- Table columns should handle the volume (no layout break)
- Consider "load more" vs pagination vs infinite scroll based on context

### 6. Long Text Overflow
**When**: User-generated content, long names, long descriptions, URLs.

**Rules**:
- Truncate with ellipsis for single-line content (max-width + overflow: hidden + text-overflow: ellipsis)
- Line clamp for multi-line content (2-3 lines with "Read more")
- Test with extremely long strings (50+ character words, no spaces)
- Test with multiple languages (German words are long, CJK characters have different widths)
- URLs should not break layouts (word-break: break-all for URLs)
- Never let text overflow its container and overlap other elements
- Tables: Define min/max column widths

### 7. Offline State
**When**: Network connection is lost.

**Rules**:
- Show a subtle, persistent banner (not a blocking modal)
- Display cached content where possible
- Disable actions that require network (with clear disabled state)
- Queue actions for when connectivity returns (if applicable)
- Auto-reconnect and remove the banner when connectivity returns
- Don't show a full-screen error — the user may be browsing cached data

### 8. Permission Denied
**When**: User doesn't have access to this content or feature.

**Rules**:
- Don't show a raw 403 page
- Explain what they can't access and why ("You don't have admin access")
- Provide a path forward ("Request access" or "Contact your admin")
- If the page has mixed permissions, hide/disable inaccessible parts rather than blocking the entire page
- Don't reveal the existence of content they can't access (security)

---

## Edge State Checklist

For every screen design, verify:

```
## Edge State Checklist: [Screen Name]

- [ ] Empty state: Designed with illustration, message, and CTA
- [ ] Loading state: Skeleton or spinner, no layout shift
- [ ] Error state: Clear message, retry action, scoped impact
- [ ] Single item: Layout works with exactly one item
- [ ] Many items: Pagination/scroll, count shown, filter available
- [ ] Long text: Truncation defined, tested with long strings
- [ ] Offline: Banner shown, cached content displayed, actions disabled
- [ ] Permission denied: Clear message, action to request access
```

Every checkbox must be addressed. If a state doesn't apply (e.g., a settings page doesn't have a "many items" state), note it as N/A with reasoning.

