Main Site ↗

performance-security

by MadAppGang24819GitHub

A comprehensive, production-ready guide covering essential performance, accessibility, and security practices for modern React applications with practical code examples.

Unlock Deep Analysis

Use AI to visualize the workflow and generate a realistic output preview for this skill.

Powered by Fastest LLM

Target Audience

React developers, frontend engineers, and technical leads building production applications who need comprehensive guidance on optimization and security.

10/10Security

Low security risk, safe to use

9
Clarity
9
Practicality
8
Quality
8
Maintainability
7
Innovation
Frontend
react-optimizationweb-securityaccessibilityperformancebest-practices
Compatible Agents
Claude Code
Claude Code
~/.claude/skills/
Codex CLI
Codex CLI
~/.codex/skills/
Gemini CLI
Gemini CLI
~/.gemini/skills/
O
OpenCode
~/.opencode/skills/
O
OpenClaw
~/.openclaw/skills/
GitHub Copilot
GitHub Copilot
~/.copilot/skills/
Cursor
Cursor
~/.cursor/skills/
W
Windsurf
~/.codeium/windsurf/skills/
C
Cline
~/.cline/skills/
R
Roo Code
~/.roo/skills/
K
Kiro
~/.kiro/skills/
J
Junie
~/.junie/skills/
A
Augment Code
~/.augment/skills/
W
Warp
~/.warp/skills/
G
Goose
~/.config/goose/skills/
SKILL.md

Performance, Accessibility & Security

Production-ready patterns for building fast, accessible, and secure React applications.

Performance Optimization

Code-Splitting

Automatic with TanStack Router:

  • File-based routing automatically code-splits by route
  • Each route is its own chunk
  • Vite handles dynamic imports efficiently

Manual code-splitting:

import { lazy, Suspense } from 'react'

// Lazy load heavy components
const HeavyChart = lazy(() => import('./HeavyChart'))

function Dashboard() {
  return (
    <Suspense fallback={<Spinner />}>
      <HeavyChart data={data} />
    </Suspense>
  )
}

Route-level lazy loading:

// src/routes/dashboard.lazy.tsx
export const Route = createLazyFileRoute('/dashboard')({
  component: DashboardComponent,
})

React Compiler First

The React Compiler automatically optimizes performance when you write compiler-friendly code:

✅ Do:

  • Keep components pure (no side effects in render)
  • Derive values during render (don't stash in refs)
  • Keep props serializable
  • Inline event handlers (unless they close over large objects)

❌ Avoid:

  • Mutating props or state
  • Side effects in render phase
  • Over-using useCallback/useMemo (compiler handles this)
  • Non-serializable props (functions, symbols)

Verify optimization:

  • Check React DevTools for "Memo ✨" badge
  • Components without badge weren't optimized (check for violations)

Images & Assets

Use Vite asset pipeline:

// Imports are optimized and hashed
import logo from './logo.png'

<img src={logo} alt="Logo" />

Prefer modern formats:

// WebP for photos
<img src="/hero.webp" alt="Hero" />

// SVG for icons
import { ReactComponent as Icon } from './icon.svg'
<Icon />

Lazy load images:

<img src={imageSrc} loading="lazy" alt="Description" />

Responsive images:

<img
  srcSet="
    /image-320w.webp 320w,
    /image-640w.webp 640w,
    /image-1280w.webp 1280w
  "
  sizes="(max-width: 640px) 100vw, 640px"
  src="/image-640w.webp"
  alt="Description"
/>

Bundle Analysis

# Build with analysis
npx vite build --mode production

# Visualize bundle
pnpm add -D rollup-plugin-visualizer
// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [
    react(),
    visualizer({ open: true }),
  ],
})

Performance Checklist

  • Code-split routes and heavy components
  • Verify React Compiler optimizations (✨ badges)
  • Optimize images (WebP, lazy loading, responsive)
  • Prefetch critical data in route loaders
  • Use TanStack Query for automatic deduplication
  • Set appropriate staleTime per query
  • Minimize bundle size (check with visualizer)
  • Enable compression (gzip/brotli on server)

Accessibility (a11y)

Semantic HTML

✅ Use semantic elements:

// Good
<nav><a href="/about">About</a></nav>
<button onClick={handleClick}>Submit</button>
<main><article>Content</article></main>

// Bad
<div onClick={handleNav}>About</div>
<div onClick={handleClick}>Submit</div>
<div><div>Content</div></div>

ARIA When Needed

Only add ARIA when semantic HTML isn't enough:

// Custom select component
<div
  role="listbox"
  aria-label="Select country"
  aria-activedescendant={activeId}
>
  <div role="option" id="us">United States</div>
  <div role="option" id="uk">United Kingdom</div>
</div>

// Loading state
<button aria-busy={isLoading} disabled={isLoading}>
  {isLoading ? 'Loading...' : 'Submit'}
</button>

Keyboard Navigation

Ensure all interactive elements are keyboard accessible:

function Dialog({ isOpen, onClose }: DialogProps) {
  useEffect(() => {
    const handleEscape = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose()
    }

    if (isOpen) {
      document.addEventListener('keydown', handleEscape)
      return () => document.removeEventListener('keydown', handleEscape)
    }
  }, [isOpen, onClose])

  return isOpen ? (
    <div role="dialog" aria-modal="true">
      {/* Focus trap implementation */}
      <button onClick={onClose} aria-label="Close dialog">×</button>
      {/* Dialog content */}
    </div>
  ) : null
}

Testing with React Testing Library

Use accessible queries (by role/label):

import { render, screen } from '@testing-library/react'

test('button is accessible', () => {
  render(<button>Submit</button>)

  // ✅ Good - query by role
  const button = screen.getByRole('button', { name: /submit/i })
  expect(button).toBeInTheDocument()

  // ❌ Avoid - query by test ID
  const button = screen.getByTestId('submit-button')
})

Common accessible queries:

// By role (preferred)
screen.getByRole('button', { name: /submit/i })
screen.getByRole('textbox', { name: /email/i })
screen.getByRole('heading', { level: 1 })

// By label
screen.getByLabelText(/email address/i)

// By text
screen.getByText(/welcome/i)

Color Contrast

  • Ensure 4.5:1 contrast ratio for normal text
  • Ensure 3:1 contrast ratio for large text (18pt+)
  • Don't rely on color alone for meaning
  • Test with browser DevTools accessibility panel

Accessibility Checklist

  • Use semantic HTML elements
  • Add alt text to all images
  • Ensure keyboard navigation works
  • Provide focus indicators
  • Test with screen reader (NVDA/JAWS/VoiceOver)
  • Verify color contrast meets WCAG AA
  • Use React Testing Library accessible queries
  • Add skip links for main content
  • Ensure form inputs have labels

Security

Never Ship Secrets

❌ Wrong - secrets in code:

const API_KEY = 'sk_live_abc123' // Exposed in bundle!

✅ Correct - environment variables:

// Only VITE_* variables are exposed to client
const API_KEY = import.meta.env.VITE_PUBLIC_KEY

In .env.local (not committed):

VITE_PUBLIC_KEY=pk_live_abc123  # Public key only!

Backend handles secrets:

// Frontend calls backend, backend uses secret API key
await apiClient.post('/process-payment', { amount, token })
// Backend has access to SECRET_KEY via server env

Validate All Untrusted Data

At boundaries (API responses):

import { z } from 'zod'

const UserSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.string().email(),
})

async function fetchUser(id: string) {
  const response = await apiClient.get(`/users/${id}`)

  // Validate response
  return UserSchema.parse(response.data)
}

User input:

const formSchema = z.object({
  email: z.string().email('Invalid email'),
  password: z.string().min(8, 'Password must be 8+ characters'),
})

type FormData = z.infer<typeof formSchema>

function LoginForm() {
  const handleSubmit = (data: unknown) => {
    const result = formSchema.safeParse(data)

    if (!result.success) {
      setErrors(result.error.errors)
      return
    }

    // result.data is typed and validated
    login(result.data)
  }
}

XSS Prevention

React automatically escapes content in JSX:

// ✅ Safe - React escapes
<div>{userInput}</div>

// ❌ Dangerous - bypasses escaping
<div dangerouslySetInnerHTML={{ __html: userInput }} />

If you must use HTML:

import DOMPurify from 'dompurify'

<div dangerouslySetInnerHTML={{
  __html: DOMPurify.sanitize(trustedHTML)
}} />

Content Security Policy

Add CSP headers on server:

# nginx example
add_header Content-Security-Policy "
  default-src 'self';
  script-src 'self' 'unsafe-inline';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  font-src 'self' data:;
  connect-src 'self' https://api.example.com;
";

Dependency Security

Pin versions in package.json:

{
  "dependencies": {
    "react": "19.0.0",  // Exact version
    "@tanstack/react-query": "^5.59.0"  // Allow patches
  }
}

Audit regularly:

pnpm audit
pnpm audit --fix

Use Renovate or Dependabot:

// .github/renovate.json
{
  "extends": ["config:base"],
  "automerge": true,
  "major": { "automerge": false }
}

CI Security

Run with --ignore-scripts:

# Prevents malicious post-install scripts
pnpm install --ignore-scripts

Scan for secrets:

# Add to CI
git-secrets --scan

Security Checklist

  • Never commit secrets or API keys
  • Only expose VITE_* env vars to client
  • Validate all API responses with Zod
  • Sanitize user-generated HTML (if needed)
  • Set Content Security Policy headers
  • Pin dependency versions
  • Run pnpm audit regularly
  • Enable Renovate/Dependabot
  • Use --ignore-scripts in CI
  • Implement proper authentication flow

Related Skills

  • core-principles - Project structure and standards
  • react-patterns - Compiler-friendly code
  • tanstack-query - Performance via caching and deduplication
  • tooling-setup - TypeScript strict mode for type safety

Source: https://github.com/MadAppGang/claude-code#plugins~frontend~skills~performance-security

Content curated from original sources, copyright belongs to authors

Grade A
8.4AI Score
Best Practices
Checking...
Try this Skill

User Rating

USER RATING

0UP
0DOWN
Loading files...

WORKS WITH

Claude Code
Claude
Codex CLI
Codex
Gemini CLI
Gemini
O
OpenCode
O
OpenClaw
GitHub Copilot
Copilot
Cursor
Cursor
W
Windsurf
C
Cline
R
Roo
K
Kiro
J
Junie
A
Augment
W
Warp
G
Goose