Back to Skills

Senior Frontend

Frontend development skill for React, Next.js, TypeScript, and Tailwind CSS applications. Use when building React components, optimizing Next.js performance, analyzing bundle sizes, scaffolding frontend projects, implementing accessibility, or reviewing frontend code quality.

$ npx promptcreek add senior-frontend

Auto-detects your installed agents and installs the skill to each one.

What This Skill Does

This skill provides frontend development patterns, performance optimization techniques, and automation tools for React/Next.js applications. It helps scaffold new projects, generate components, and analyze bundle sizes. It's designed for frontend developers who need to build and optimize React/Next.js applications.

When to Use

  • Scaffold a new Next.js project.
  • Generate a React component.
  • Analyze the bundle size of a frontend application.
  • Implement a React pattern.
  • Optimize a Next.js application.
  • Add accessibility features to a component.

Key Features

Scaffolds new Next.js and React projects with TypeScript and Tailwind CSS.
Generates components with best practice configurations.
Analyzes bundle sizes to identify optimization opportunities.
Provides guidance on React patterns.
Offers Next.js optimization techniques.
Supports accessibility and testing best practices.

Installation

Run in your project directory:
$ npx promptcreek add senior-frontend

Auto-detects your installed agents (Claude Code, Cursor, Codex, etc.) and installs the skill to each one.

View Full Skill Content

Senior Frontend

Frontend development patterns, performance optimization, and automation tools for React/Next.js applications.

Table of Contents


Project Scaffolding

Generate a new Next.js or React project with TypeScript, Tailwind CSS, and best practice configurations.

Workflow: Create New Frontend Project

  • Run the scaffolder with your project name and template:

python scripts/frontend_scaffolder.py my-app --template nextjs

  • Add optional features (auth, api, forms, testing, storybook):

python scripts/frontend_scaffolder.py dashboard --template nextjs --features auth,api

  • Navigate to the project and install dependencies:

cd my-app && npm install

  • Start the development server:

npm run dev

Scaffolder Options

| Option | Description |

|--------|-------------|

| --template nextjs | Next.js 14+ with App Router and Server Components |

| --template react | React + Vite with TypeScript |

| --features auth | Add NextAuth.js authentication |

| --features api | Add React Query + API client |

| --features forms | Add React Hook Form + Zod validation |

| --features testing | Add Vitest + Testing Library |

| --dry-run | Preview files without creating them |

Generated Structure (Next.js)

my-app/

├── app/

│ ├── layout.tsx # Root layout with fonts

│ ├── page.tsx # Home page

│ ├── globals.css # Tailwind + CSS variables

│ └── api/health/route.ts

├── components/

│ ├── ui/ # Button, Input, Card

│ └── layout/ # Header, Footer, Sidebar

├── hooks/ # useDebounce, useLocalStorage

├── lib/ # utils (cn), constants

├── types/ # TypeScript interfaces

├── tailwind.config.ts

├── next.config.js

└── package.json


Component Generation

Generate React components with TypeScript, tests, and Storybook stories.

Workflow: Create a New Component

  • Generate a client component:

python scripts/component_generator.py Button --dir src/components/ui

  • Generate a server component:

python scripts/component_generator.py ProductCard --type server

  • Generate with test and story files:

python scripts/component_generator.py UserProfile --with-test --with-story

  • Generate a custom hook:

python scripts/component_generator.py FormValidation --type hook

Generator Options

| Option | Description |

|--------|-------------|

| --type client | Client component with 'use client' (default) |

| --type server | Async server component |

| --type hook | Custom React hook |

| --with-test | Include test file |

| --with-story | Include Storybook story |

| --flat | Create in output dir without subdirectory |

| --dry-run | Preview without creating files |

Generated Component Example

'use client';

import { useState } from 'react';

import { cn } from '@/lib/utils';

interface ButtonProps {

className?: string;

children?: React.ReactNode;

}

export function Button({ className, children }: ButtonProps) {

return (

<div className={cn('', className)}>

{children}

</div>

);

}


Bundle Analysis

Analyze package.json and project structure for bundle optimization opportunities.

Workflow: Optimize Bundle Size

  • Run the analyzer on your project:

python scripts/bundle_analyzer.py /path/to/project

  • Review the health score and issues:

Bundle Health Score: 75/100 (C)

HEAVY DEPENDENCIES:

moment (290KB)

Alternative: date-fns (12KB) or dayjs (2KB)

lodash (71KB)

Alternative: lodash-es with tree-shaking

  • Apply the recommended fixes by replacing heavy dependencies.
  • Re-run with verbose mode to check import patterns:

python scripts/bundle_analyzer.py . --verbose

Bundle Score Interpretation

| Score | Grade | Action |

|-------|-------|--------|

| 90-100 | A | Bundle is well-optimized |

| 80-89 | B | Minor optimizations available |

| 70-79 | C | Replace heavy dependencies |

| 60-69 | D | Multiple issues need attention |

| 0-59 | F | Critical bundle size problems |

Heavy Dependencies Detected

The analyzer identifies these common heavy packages:

| Package | Size | Alternative |

|---------|------|-------------|

| moment | 290KB | date-fns (12KB) or dayjs (2KB) |

| lodash | 71KB | lodash-es with tree-shaking |

| axios | 14KB | Native fetch or ky (3KB) |

| jquery | 87KB | Native DOM APIs |

| @mui/material | Large | shadcn/ui or Radix UI |


React Patterns

Reference: references/react_patterns.md

Compound Components

Share state between related components:

const Tabs = ({ children }) => {

const [active, setActive] = useState(0);

return (

<TabsContext.Provider value={{ active, setActive }}>

{children}

</TabsContext.Provider>

);

};

Tabs.List = TabList;

Tabs.Panel = TabPanel;

// Usage

<Tabs>

<Tabs.List>

<Tabs.Tab>One</Tabs.Tab>

<Tabs.Tab>Two</Tabs.Tab>

</Tabs.List>

<Tabs.Panel>Content 1</Tabs.Panel>

<Tabs.Panel>Content 2</Tabs.Panel>

</Tabs>

Custom Hooks

Extract reusable logic:

function useDebounce<T>(value: T, delay = 500): T {

const [debouncedValue, setDebouncedValue] = useState(value);

useEffect(() => {

const timer = setTimeout(() => setDebouncedValue(value), delay);

return () => clearTimeout(timer);

}, [value, delay]);

return debouncedValue;

}

// Usage

const debouncedSearch = useDebounce(searchTerm, 300);

Render Props

Share rendering logic:

function DataFetcher({ url, render }) {

const [data, setData] = useState(null);

const [loading, setLoading] = useState(true);

useEffect(() => {

fetch(url).then(r => r.json()).then(setData).finally(() => setLoading(false));

}, [url]);

return render({ data, loading });

}

// Usage

<DataFetcher

url="/api/users"

render={({ data, loading }) =>

loading ? <Spinner /> : <UserList users={data} />

}

/>


Next.js Optimization

Reference: references/nextjs_optimization_guide.md

Server vs Client Components

Use Server Components by default. Add 'use client' only when you need:

  • Event handlers (onClick, onChange)
  • State (useState, useReducer)
  • Effects (useEffect)
  • Browser APIs
// Server Component (default) - no 'use client'

async function ProductPage({ params }) {

const product = await getProduct(params.id); // Server-side fetch

return (

<div>

<h1>{product.name}</h1>

<AddToCartButton productId={product.id} /> {/ Client component /}

</div>

);

}

// Client Component

'use client';

function AddToCartButton({ productId }) {

const [adding, setAdding] = useState(false);

return <button onClick={() => addToCart(productId)}>Add</button>;

}

Image Optimization

import Image from 'next/image';

// Above the fold - load immediately

<Image

src="/hero.jpg"

alt="Hero"

width={1200}

height={600}

priority

/>

// Responsive image with fill

<div className="relative aspect-video">

<Image

src="/product.jpg"

alt="Product"

fill

sizes="(max-width: 768px) 100vw, 50vw"

className="object-cover"

/>

</div>

Data Fetching Patterns

// Parallel fetching

async function Dashboard() {

const [user, stats] = await Promise.all([

getUser(),

getStats()

]);

return <div>...</div>;

}

// Streaming with Suspense

async function ProductPage({ params }) {

return (

<div>

<ProductDetails id={params.id} />

<Suspense fallback={<ReviewsSkeleton />}>

<Reviews productId={params.id} />

</Suspense>

</div>

);

}


Accessibility and Testing

Reference: references/frontend_best_practices.md

Accessibility Checklist

  • Semantic HTML: Use proper elements (
  • Keyboard Navigation: All interactive elements focusable
  • ARIA Labels: Provide labels for icons and complex widgets
  • Color Contrast: Minimum 4.5:1 for normal text
  • Focus Indicators: Visible focus states
// Accessible button

<button

type="button"

aria-label="Close dialog"

onClick={onClose}

className="focus-visible:ring-2 focus-visible:ring-blue-500"

>

<XIcon aria-hidden="true" />

</button>

// Skip link for keyboard users

<a href="#main-content" className="sr-only focus:not-sr-only">

Skip to main content

</a>

Testing Strategy

// Component test with React Testing Library

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

import userEvent from '@testing-library/user-event';

test('button triggers action on click', async () => {

const onClick = vi.fn();

render(<Button onClick={onClick}>Click me</Button>);

await userEvent.click(screen.getByRole('button'));

expect(onClick).toHaveBeenCalledTimes(1);

});

// Test accessibility

test('dialog is accessible', async () => {

render(<Dialog open={true} title="Confirm" />);

expect(screen.getByRole('dialog')).toBeInTheDocument();

expect(screen.getByRole('dialog')).toHaveAttribute('aria-labelledby');

});


Quick Reference

Common Next.js Config

// next.config.js

const nextConfig = {

images: {

remotePatterns: [{ hostname: "cdnexamplecom" }],

formats: ['image/avif', 'image/webp'],

},

experimental: {

optimizePackageImports: ['lucide-react', '@heroicons/react'],

},

};

Tailwind CSS Utilities

// Conditional classes with cn()

import { cn } from '@/lib/utils';

<button className={cn(

'px-4 py-2 rounded',

variant === 'primary' && 'bg-blue-500 text-white',

disabled && 'opacity-50 cursor-not-allowed'

)} />

TypeScript Patterns

// Props with children

interface CardProps {

className?: string;

children: React.ReactNode;

}

// Generic component

interface ListProps<T> {

items: T[];

renderItem: (item: T) => React.ReactNode;

}

function List<T>({ items, renderItem }: ListProps<T>) {

return <ul>{items.map(renderItem)}</ul>;

}


Resources

  • React Patterns: references/react_patterns.md
  • Next.js Optimization: references/nextjs_optimization_guide.md
  • Best Practices: references/frontend_best_practices.md
0Installs
0Views

Supported Agents

Claude CodeCursorCodexGemini CLIAiderWindsurfOpenClaw

Details

License
MIT
Source
seeded
Published
3/17/2026

Related Skills