senior-frontend

Frontend development skill for React, Next.js, TypeScript, and Tailwind CSS applications. Use when building React components, optimizing Next.js performance,…

INSTALLATION
npx skills add https://github.com/alirezarezvani/claude-skills --skill senior-frontend
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

Senior Frontend

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

Table of Contents

  • [Project Scaffolding](#project-scaffolding)
  • [Component Generation](#component-generation)
  • [Bundle Analysis](#bundle-analysis)
  • [React Patterns](#react-patterns)
  • [Next.js Optimization](#nextjs-optimization)
  • [Accessibility and Testing](#accessibility-and-testing)

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

OptionDescription
--template nextjsNext.js 14+ with App Router and Server Components
--template reactReact + Vite with TypeScript
--features authAdd NextAuth.js authentication
--features apiAdd React Query + API client
--features formsAdd React Hook Form + Zod validation
--features testingAdd Vitest + Testing Library
--dry-runPreview 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

OptionDescription
--type clientClient component with 'use client' (default)
--type serverAsync server component
--type hookCustom React hook
--with-testInclude test file
--with-storyInclude Storybook story
--flatCreate in output dir without subdirectory
--dry-runPreview 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

ScoreGradeAction
90-100ABundle is well-optimized
80-89BMinor optimizations available
70-79CReplace heavy dependencies
60-69DMultiple issues need attention
0-59FCritical bundle size problems

Heavy Dependencies Detected

The analyzer identifies these common heavy packages:

PackageSizeAlternative
moment290KBdate-fns (12KB) or dayjs (2KB)
lodash71KBlodash-es with tree-shaking
axios14KBNative fetch or ky (3KB)
jquery87KBNative DOM APIs
@mui/materialLargeshadcn/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 (<button>, <nav>, <main>)
  • 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: [{ protocol: 'https', hostname: 'cdn.example.com' }],

    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
  • Forcing-question library (Matt Pocock grill): references/forcing_questions.md
  • Composition map (which specialist to fork into): references/composition_map.md

Assumptions and Verifiable Success Criteria (Karpathy discipline)

Before this skill scaffolds a component, recommends a framework, or audits a bundle, the following four assumptions MUST be surfaced.

  • Primary user device + network — mobile-4G, desktop-fiber, low-end-Android, or corporate-network. Drives every perf decision.
  • LCP target in milliseconds — a single number, not "fast." Drives bundle budget and rendering choice.
  • SEO-dependent vs. auth-walled — drives rendering (SSR/SSG/RSC vs. SPA).
  • WCAG target + named a11y owner — AA, AAA, or best-effort. Drives a11y investment and CI gates.

Verifiable success criteria (Karpathy #4) — every recommendation must include:

  • Core Web Vitals targets (LCP, INP, CLS) at p75 on the primary device
  • A per-route JS bundle budget in KB-gzip
  • A Lighthouse a11y floor + perf floor

If any of those three is not stated, the recommendation is incomplete — return to Q2 of the forcing-question library.

The scripts/frontend_decision_engine.py tool encodes these checks: it refuses to recommend a profile without the four assumption inputs and prints the verifiable thresholds for the matched profile.

Customization profiles

Four built-in profiles in profiles/ calibrate every recommendation:

ProfileWhen to pickLCP target (mobile-4G p75)Bundle budget
next-app-routerSaaS customer-facing, SEO + dynamic, RSC-first2000ms150 KB-gzip / route
remix-or-sveltekitMobile-4G primary, low-JS-first, progressive enhancement1500ms80 KB-gzip / route
vite-spaAuth-walled app, desktop/corporate primary2500ms200 KB init + 80 KB / route
astro-or-staticMarketing / docs / blog, near-zero write, SEO-critical1200ms30 KB JS / page

Pick a profile via:

python scripts/frontend_decision_engine.py \

  --primary-device mobile-4g --lcp-target-ms 2000 \

  --seo-dependent true --auth-walled false --team-size 5

The tool returns the best-fit profile, the runner-up tradeoff (if within 15%), the stack picks, the anti-patterns to avoid on that profile, and the required CI gates.

To add a custom profile (e.g., your org's internal-tool defaults): copy profiles/vite-spa.json to profiles/<your-org>.json and adjust constraints + success_thresholds.

Composition map

This skill does NOT reimplement scope owned by the POWERFUL-tier specialists. It forks into them. See references/composition_map.md for the full routing table. Key forks:

ConcernFork into
WCAG audit, contrast, screen-readerengineering-team/skills/a11y-audit/
Bundle profiling + runtime perfengineering/skills/performance-profiler/
Cinematic / scroll-storytelling landingengineering-team/skills/epic-design/
Apple HIG (iOS / macOS / visionOS)product-team/skills/apple-hig-expert/
Pre-commit Karpathy reviewengineering/karpathy-coder/
Pre-flight architecture grillengineering/grill-me/

The cs-frontend-engineer agent orchestrates these forks via context: fork. Invoke it from another agent with Agent({subagent_type: "cs-frontend-engineer", prompt: "..."}) or via /cs-frontend-review <your problem>.

Forcing-question library (Matt Pocock grill)

Before locking any framework or rendering decision, walk the seven forcing questions in references/forcing_questions.md. Discipline:

  • One question per turn. No bundling.
  • Always recommend the answer with cited canon.
  • Track answers in /tmp/frontend-grill-<date>.md.
  • If a kill criterion trips, stop. Don't scaffold around an unresolved gap.
  • After Q7, run frontend_decision_engine.py with the seven answers.

Summary:

  • Primary device + network?
  • LCP target in ms (and INP, CLS)?
  • RSC / SPA / SSR / SSG — pick and defend?
  • JS bundle budget per route?
  • SEO-dependent or auth-walled?
  • Design-system source of truth?
  • WCAG target + named a11y owner?

Invocation from other agents and skills

Three surfaces:

  • Slash command: /cs-frontend-review <prompt> — full grill + decision engine + composition routing.
  • Agent subagent: Agent({subagent_type: "cs-frontend-engineer", prompt: "..."}) — forks context, returns ≤ 200-word digest.
  • Direct tool call: python scripts/frontend_decision_engine.py ... — deterministic profile match when inputs are known.

See agents/engineering/cs-frontend-engineer.md for the full invocation contract.

BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card