{"id":"e9ecbcaa-3178-46ed-af4a-c98b526ca1ed","shortId":"rZ2qHA","kind":"skill","title":"react-ui-patterns","tagline":"Modern React UI patterns for loading states, error handling, and data fetching. Use when building UI components, handling async data, or managing UI states.","description":"# React UI Patterns\n\n## Core Principles\n\n1. **Never show stale UI** - Loading spinners only when actually loading\n2. **Always surface errors** - Users must know when something fails\n3. **Optimistic updates** - Make the UI feel instant\n4. **Progressive disclosure** - Show content as it becomes available\n5. **Graceful degradation** - Partial data is better than no data\n\n## Loading State Patterns\n\n### The Golden Rule\n\n**Show loading indicator ONLY when there's no data to display.**\n\n```typescript\n// CORRECT - Only show loading when no data exists\nconst { data, loading, error } = useGetItemsQuery();\n\nif (error) return <ErrorState error={error} onRetry={refetch} />;\nif (loading && !data) return <LoadingState />;\nif (!data?.items.length) return <EmptyState />;\n\nreturn <ItemList items={data.items} />;\n```\n\n```typescript\n// WRONG - Shows spinner even when we have cached data\nif (loading) return <LoadingState />; // Flashes on refetch!\n```\n\n### Loading State Decision Tree\n\n```\nIs there an error?\n  → Yes: Show error state with retry option\n  → No: Continue\n\nIs it loading AND we have no data?\n  → Yes: Show loading indicator (spinner/skeleton)\n  → No: Continue\n\nDo we have data?\n  → Yes, with items: Show the data\n  → Yes, but empty: Show empty state\n  → No: Show loading (fallback)\n```\n\n### Skeleton vs Spinner\n\n| Use Skeleton When | Use Spinner When |\n|-------------------|------------------|\n| Known content shape | Unknown content shape |\n| List/card layouts | Modal actions |\n| Initial page load | Button submissions |\n| Content placeholders | Inline operations |\n\n## Error Handling Patterns\n\n### The Error Handling Hierarchy\n\n```\n1. Inline error (field-level) → Form validation errors\n2. Toast notification → Recoverable errors, user can retry\n3. Error banner → Page-level errors, data still partially usable\n4. Full error screen → Unrecoverable, needs user action\n```\n\n### Always Show Errors\n\n**CRITICAL: Never swallow errors silently.**\n\n```typescript\n// CORRECT - Error always surfaced to user\nconst [createItem, { loading }] = useCreateItemMutation({\n  onCompleted: () => {\n    toast.success({ title: 'Item created' });\n  },\n  onError: (error) => {\n    console.error('createItem failed:', error);\n    toast.error({ title: 'Failed to create item' });\n  },\n});\n\n// WRONG - Error silently caught, user has no idea\nconst [createItem] = useCreateItemMutation({\n  onError: (error) => {\n    console.error(error); // User sees nothing!\n  },\n});\n```\n\n### Error State Component Pattern\n\n```typescript\ninterface ErrorStateProps {\n  error: Error;\n  onRetry?: () => void;\n  title?: string;\n}\n\nconst ErrorState = ({ error, onRetry, title }: ErrorStateProps) => (\n  <div className=\"error-state\">\n    <Icon name=\"exclamation-circle\" />\n    <h3>{title ?? 'Something went wrong'}</h3>\n    <p>{error.message}</p>\n    {onRetry && (\n      <Button onClick={onRetry}>Try Again</Button>\n    )}\n  </div>\n);\n```\n\n## Button State Patterns\n\n### Button Loading State\n\n```tsx\n<Button\n  onClick={handleSubmit}\n  isLoading={isSubmitting}\n  disabled={!isValid || isSubmitting}\n>\n  Submit\n</Button>\n```\n\n### Disable During Operations\n\n**CRITICAL: Always disable triggers during async operations.**\n\n```tsx\n// CORRECT - Button disabled while loading\n<Button\n  disabled={isSubmitting}\n  isLoading={isSubmitting}\n  onClick={handleSubmit}\n>\n  Submit\n</Button>\n\n// WRONG - User can tap multiple times\n<Button onClick={handleSubmit}>\n  {isSubmitting ? 'Submitting...' : 'Submit'}\n</Button>\n```\n\n## Empty States\n\n### Empty State Requirements\n\nEvery list/collection MUST have an empty state:\n\n```tsx\n// WRONG - No empty state\nreturn <FlatList data={items} />;\n\n// CORRECT - Explicit empty state\nreturn (\n  <FlatList\n    data={items}\n    ListEmptyComponent={<EmptyState />}\n  />\n);\n```\n\n### Contextual Empty States\n\n```tsx\n// Search with no results\n<EmptyState\n  icon=\"search\"\n  title=\"No results found\"\n  description=\"Try different search terms\"\n/>\n\n// List with no items yet\n<EmptyState\n  icon=\"plus-circle\"\n  title=\"No items yet\"\n  description=\"Create your first item\"\n  action={{ label: 'Create Item', onClick: handleCreate }}\n/>\n```\n\n## Form Submission Pattern\n\n```tsx\nconst MyForm = () => {\n  const [submit, { loading }] = useSubmitMutation({\n    onCompleted: handleSuccess,\n    onError: handleError,\n  });\n\n  const handleSubmit = async () => {\n    if (!isValid) {\n      toast.error({ title: 'Please fix errors' });\n      return;\n    }\n    await submit({ variables: { input: values } });\n  };\n\n  return (\n    <form>\n      <Input\n        value={values.name}\n        onChange={handleChange('name')}\n        error={touched.name ? errors.name : undefined}\n      />\n      <Button\n        type=\"submit\"\n        onClick={handleSubmit}\n        disabled={!isValid || loading}\n        isLoading={loading}\n      >\n        Submit\n      </Button>\n    </form>\n  );\n};\n```\n\n## Anti-Patterns\n\n### Loading States\n\n```typescript\n// WRONG - Spinner when data exists (causes flash)\nif (loading) return <Spinner />;\n\n// CORRECT - Only show loading without data\nif (loading && !data) return <Spinner />;\n```\n\n### Error Handling\n\n```typescript\n// WRONG - Error swallowed\ntry {\n  await mutation();\n} catch (e) {\n  console.log(e); // User has no idea!\n}\n\n// CORRECT - Error surfaced\nonError: (error) => {\n  console.error('operation failed:', error);\n  toast.error({ title: 'Operation failed' });\n}\n```\n\n### Button States\n\n```typescript\n// WRONG - Button not disabled during submission\n<Button onClick={submit}>Submit</Button>\n\n// CORRECT - Disabled and shows loading\n<Button onClick={submit} disabled={loading} isLoading={loading}>\n  Submit\n</Button>\n```\n\n## Checklist\n\nBefore completing any UI component:\n\n**UI States:**\n- [ ] Error state handled and shown to user\n- [ ] Loading state shown only when no data exists\n- [ ] Empty state provided for collections\n- [ ] Buttons disabled during async operations\n- [ ] Buttons show loading indicator when appropriate\n\n**Data & Mutations:**\n- [ ] Mutations have onError handler\n- [ ] All user actions have feedback (toast/visual)\n\n## Integration with Other Skills\n\n- **graphql-schema**: Use mutation patterns with proper error handling\n- **testing-patterns**: Test all UI states (loading, error, empty, success)\n- **formik-patterns**: Apply form submission patterns\n\n## When to Use\nThis skill is applicable to execute the workflow or actions described in the overview.\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.","tags":["react","patterns","antigravity","awesome","skills","sickn33","agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows"],"capabilities":["skill","source-sickn33","skill-react-ui-patterns","topic-agent-skills","topic-agentic-skills","topic-ai-agent-skills","topic-ai-agents","topic-ai-coding","topic-ai-workflows","topic-antigravity","topic-antigravity-skills","topic-claude-code","topic-claude-code-skills","topic-codex-cli","topic-codex-skills"],"categories":["antigravity-awesome-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/react-ui-patterns","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add sickn33/antigravity-awesome-skills","source_repo":"https://github.com/sickn33/antigravity-awesome-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 37911 github stars · SKILL.md body (6,684 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T18:51:37.114Z","embedding":null,"createdAt":"2026-04-18T20:34:53.271Z","updatedAt":"2026-05-18T18:51:37.114Z","lastSeenAt":"2026-05-18T18:51:37.114Z","tsv":"'1':34,236 '2':45,245 '3':55,253 '4':63,264 '5':72 'action':219,271,465,652,700 'actual':43 'alway':46,272,283,376 'anti':524 'anti-pattern':523 'appli':684 'applic':694 'appropri':643 'ask':738 'async':23,380,487,636 'avail':71 'await':496,556 'banner':255 'becom':70 'better':78 'boundari':746 'build':19 'button':223,351,356,359,363,384,388,402,512,579,583,588,597,633,638 'cach':141 'catch':558 'caught':311 'caus':534 'checklist':605 'circl':455 'clarif':740 'clear':713 'collect':632 'complet':607 'compon':21,328,610 'console.error':298,321,571 'console.log':560 'const':108,287,316,339,475,477,485 'content':67,211,214,225 'contextu':438 'continu':165,180 'core':32 'correct':100,281,383,429,539,566,592 'creat':295,306,461,467 'createitem':288,299,317 'criteria':749 'critic':275,375 'data':15,24,76,81,96,106,109,123,126,142,173,184,190,260,427,435,532,544,547,626,644 'data.items':132 'decis':151 'degrad':74 'describ':701,717 'descript':460 'disabl':368,372,377,385,389,517,585,593,600,634 'disclosur':65 'display':98 'e':559,561 'empti':193,195,408,410,418,423,431,439,628,679 'emptyst':451 'environ':729 'environment-specif':728 'error':12,48,111,114,117,118,156,159,229,233,238,244,249,254,259,266,274,278,282,297,301,309,320,322,326,333,334,341,494,508,549,553,567,570,574,613,668,678 'error.message':349 'errors.name':510 'errorst':116,340 'errorstateprop':332,344 'even':137 'everi':413 'execut':696 'exist':107,533,627 'expert':734 'explicit':430 'fail':54,300,304,573,578 'fallback':200 'feedback':654 'feel':61 'fetch':16 'field':240 'field-level':239 'first':463 'fix':493 'flash':146,535 'flatlist':426,434 'form':242,471,685 'formik':682 'formik-pattern':681 'full':265 'golden':86 'grace':73 'graphql':661 'graphql-schema':660 'handl':13,22,230,234,550,615,669 'handlechang':506 'handlecr':470 'handleerror':484 'handler':649 'handlesubmit':365,394,404,486,516 'handlesuccess':482 'hierarchi':235 'icon':452 'idea':315,565 'indic':90,177,641 'initi':220 'inlin':227,237 'input':499,502,743 'instant':62 'integr':656 'interfac':331 'isload':366,391,520,602 'issubmit':367,370,390,392,405 'isvalid':369,489,518 'item':131,187,294,307,428,436,449,458,464,468 'itemlist':130 'items.length':127 'know':51 'known':210 'label':466 'layout':217 'level':241,258 'limit':705 'list':446 'list/card':216 'list/collection':414 'listemptycompon':437 'load':10,39,44,82,89,103,110,122,144,149,168,176,199,222,289,360,387,479,519,521,526,537,542,546,596,601,603,620,640,677 'make':58 'manag':26 'match':714 'miss':751 'modal':218 'modern':5 'multipl':400 'must':50,415 'mutat':557,645,646,664 'myform':476 'name':507 'need':269 'never':35,276 'noth':325 'notif':247 'onchang':505 'onclick':352,364,393,403,469,515,589,598 'oncomplet':291,481 'onerror':296,319,483,569,648 'onretri':119,335,342,350,353 'oper':228,374,381,572,577,637 'optimist':56 'option':163 'output':723 'overview':704 'page':221,257 'page-level':256 'partial':75,262 'pattern':4,8,31,84,231,329,358,473,525,665,672,683,687 'permiss':744 'placehold':226 'pleas':492 'plus':454 'plus-circl':453 'principl':33 'progress':64 'proper':667 'provid':630 'react':2,6,29 'react-ui-pattern':1 'recover':248 'refetch':120,148 'requir':412,742 'result':445 'retri':162,252 'return':115,124,128,129,145,425,433,495,501,538,548 'review':735 'rule':87 'safeti':745 'schema':662 'scope':716 'screen':267 'search':442 'see':324 'shape':212,215 'show':36,66,88,102,135,158,175,188,194,198,273,541,595,639 'shown':617,622 'silent':279,310 'skeleton':201,205 'skill':659,692,708 'skill-react-ui-patterns' 'someth':53,346 'source-sickn33' 'specif':730 'spinner':40,136,203,208,530 'spinner/skeleton':178 'stale':37 'state':11,28,83,150,160,196,327,357,361,409,411,419,424,432,440,527,580,612,614,621,629,676 'still':261 'stop':736 'string':338 'submiss':224,472,587,686 'submit':371,395,406,407,478,497,514,522,590,591,599,604 'substitut':726 'success':680,748 'surfac':47,284,568 'swallow':277,554 'tap':399 'task':712 'test':671,673,732 'testing-pattern':670 'time':401 'titl':293,303,337,343,345,456,491,576 'toast':246 'toast.error':302,490,575 'toast.success':292 'toast/visual':655 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agent-skills' 'topic-ai-agents' 'topic-ai-coding' 'topic-ai-workflows' 'topic-antigravity' 'topic-antigravity-skills' 'topic-claude-code' 'topic-claude-code-skills' 'topic-codex-cli' 'topic-codex-skills' 'touched.name':509 'treat':721 'tree':152 'tri':354,555 'trigger':378 'tsx':362,382,420,441,474 'type':513 'typescript':99,133,280,330,528,551,581 'ui':3,7,20,27,30,38,60,609,611,675 'undefin':511 'unknown':213 'unrecover':268 'updat':57 'usabl':263 'use':17,204,207,663,690,706 'usecreateitemmut':290,318 'usegetitemsqueri':112 'user':49,250,270,286,312,323,397,562,619,651 'usesubmitmut':480 'valid':243,731 'valu':500,503 'values.name':504 'variabl':498 'void':336 'vs':202 'went':347 'without':543 'workflow':698 'wrong':134,308,348,396,421,529,552,582 'yes':157,174,185,191 'yet':450,459","prices":[{"id":"9ac38514-4e83-46bb-987e-3735e0269110","listingId":"e9ecbcaa-3178-46ed-af4a-c98b526ca1ed","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"sickn33","category":"antigravity-awesome-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T20:34:53.271Z"}],"sources":[{"listingId":"e9ecbcaa-3178-46ed-af4a-c98b526ca1ed","source":"github","sourceId":"sickn33/antigravity-awesome-skills/react-ui-patterns","sourceUrl":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/react-ui-patterns","isPrimary":false,"firstSeenAt":"2026-04-18T21:43:23.391Z","lastSeenAt":"2026-05-18T18:51:37.114Z"},{"listingId":"e9ecbcaa-3178-46ed-af4a-c98b526ca1ed","source":"skills_sh","sourceId":"sickn33/antigravity-awesome-skills/react-ui-patterns","sourceUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/react-ui-patterns","isPrimary":true,"firstSeenAt":"2026-04-18T20:34:53.271Z","lastSeenAt":"2026-05-07T22:40:39.928Z"}],"details":{"listingId":"e9ecbcaa-3178-46ed-af4a-c98b526ca1ed","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"sickn33","slug":"react-ui-patterns","github":{"repo":"sickn33/antigravity-awesome-skills","stars":37911,"topics":["agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity","antigravity-skills","claude-code","claude-code-skills","codex-cli","codex-skills","cursor","cursor-skills","developer-tools","gemini-cli","gemini-skills","kiro","mcp","skill-library"],"license":"mit","html_url":"https://github.com/sickn33/antigravity-awesome-skills","pushed_at":"2026-05-18T08:24:49Z","description":"Installable GitHub library of 1,400+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and more. Includes installer CLI, bundles, workflows, and official/community skill collections.","skill_md_sha":"56964a95a2c42c3ba176ea4e2424993a81e82c89","skill_md_path":"skills/react-ui-patterns/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/react-ui-patterns"},"layout":"multi","source":"github","category":"antigravity-awesome-skills","frontmatter":{"name":"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."},"skills_sh_url":"https://skills.sh/sickn33/antigravity-awesome-skills/react-ui-patterns"},"updatedAt":"2026-05-18T18:51:37.114Z"}}