All skills

Enforces professional frontend architecture — component structure, CSS methodology, state management, performance, and React patterns. TRIGGER when: user builds or modifies any React/Next.js component, asks about component structure, state management, CSS architecture, responsive layout, TypeScript typing, lazy loading, or frontend file organization. TRIGGER also when: user asks why frontend is slow, broken on mobile, causing re-render loops, or has hydration errors. DO NOT TRIGGER when: user is working on backend routes, database schemas, server logic, or non-frontend deployment tasks.

  • 1 file
  • 10.7 KB
  • Updated last month
  • GitHub

Use this Skill: https://skilld.dev/gh/mdzubair933/web-design-mastery-skills/frontend-engineering

This session only. Nothing lands on disk.

SKILL.md

≈154 tokens always: the name and description. ≈2.6k when used: this file.

Frontend Engineering

Enforces production-grade React/Next.js frontend architecture — clean component structure, scalable CSS, correct state management, and performance patterns that eliminate AI-slop and amateur mistakes. Primary constraint: every component must be reusable, every style must be variable-mapped, and every state update must be traceable and loop-free.

Core Rules

Rule: Isolate frontend and backend completely — separate root folders, separate servers. Why: mixing them creates ambiguous security boundaries and makes credential leaks far more likely.

Rule: Never make database calls from React/Next.js files. Why: this exposes credentials in the browser and bypasses all backend security validation. All data fetching goes through the services/ API layer only.

Rule: Never use any type in TypeScript. Why: any disables the type system entirely — bugs that TypeScript would catch at compile time become runtime crashes in production.

Rule: Never store JWT access tokens in localStorage or sessionStorage. Why: XSS scripts can read these stores; stolen tokens grant full account access. Access tokens stay in React state/context only.

Rule: Always define explicit dependency arrays in every useEffect. Why: missing dependency arrays trigger infinite render loops — these are nearly invisible during light testing but crash real browsers under load.

Component Architecture

Directory Structure (non-negotiable):

src/
├── components/
│   ├── ui/         ← reusable: Button, Input, Modal, Card, Tooltip, Label
│   ├── auth/       ← Login, Register, PasswordRecovery forms
│   └── dashboard/  ← Sidebar, DataGrid, StatsCard, NavBar
├── styles/
│   └── global.css  ← all CSS root variables live here
├── services/       ← all API call functions — never DB calls
└── app/ or pages/  ← Next.js routing only

Component Rules:

  • Build generic UI elements in components/ui/ — they must accept props for variants (Primary/Ghost/Danger) and sizes, never hardcode a style inside.
  • One component, one responsibility. If a component exceeds ~150 lines, it is doing too many things — extract sub-components.
  • Brand assets (logos, SVGs) go in public/Branding/. Custom fonts go in public/fonts/. Never inline SVGs larger than icons.

Reusability Test: Before building a new component, ask: "Have I built something similar before?" If yes, abstract the existing one into components/ui/ and reuse it. Duplication is the primary driver of unmaintainable frontends.

CSS Architecture

Tailwind + CSS Root Variables — always together: Tailwind for layout, spacing, and utility classes. CSS root variables in global.css for all brand colors, radii, and theme tokens.

/* Correct — maps to variable */
className="bg-[var(--primary)] text-[var(--foreground)]"

/* Wrong — hardcoded hex */
className="bg-[#6d28d9] text-[#111111]"

Why: Hardcoded values in 50+ components require 50+ file edits for one brand change. Variable-mapped components require editing one line in global.css.

Responsive Breakpoints — plan from the start, not as an afterthought:

  • sm: (640px) — mobile landscape
  • md: (768px) — tablet
  • lg: (1024px) — desktop
  • xl: (1280px) — wide desktop

Mobile Rules:

  • Desktop sidebars collapse to a drawer/sheet — never inline-shrink.
  • Multi-column grids stack vertically on mobile — never overflow or clip.
  • Navigation becomes a bottom bar or hamburger drawer on mobile.

A4 Print Styles (for invoice/document views):

@media print {
  body { background: white; margin: 0; }
  .sidebar, .no-print { display: none; }
  .document { width: 210mm; min-height: 297mm; padding: 20mm; }
}

State Management

Local vs. Global — use this rule:

State type Hook / Tool Examples
Isolated UI state useState Dropdown open, form input, step counter
Shared across multiple branches React Context Auth session, theme preference
Server data / async useEffect + useState or SWR API responses, user profile

State Security Rule:

  • Access tokens (JWT) → React state or Context only. Never localStorage.
  • Refresh tokens → set by backend into HttpOnly cookies. Never touch from JS.

useEffect Rules — all three are mandatory:

  1. Always define a dependency array — empty [] or specific deps, never omit.
  2. Never mutate state inside a useEffect that lists that state as a dependency — this creates an infinite loop.
  3. Cleanup subscriptions and timers in the return function of useEffect.

State-Aware Routing:

  • Authenticated user hitting /login or /register → redirect to dashboard.
  • Unauthenticated user hitting /dashboard → redirect to /login.
  • Never render protected views before auth state is confirmed.

TypeScript Patterns

Always define interfaces for:

  • API request payloads
  • API response shapes
  • Database document models
  • Component prop types
// Correct
interface Invoice {
  id: string;
  userId: string;
  amount: number;
  status: "draft" | "sent" | "paid";
  createdAt: Date;
}

// Wrong
const invoice: any = await fetchInvoice(id);

Form validation: Validate locally before posting to backend. Check required fields, string formats (email), and matching values (confirm password) client-side first — this avoids unnecessary API calls and 400 errors.

Performance

Lazy Loading: Dynamically import heavy components and secondary views so they only load when needed. Why: reduces initial bundle size and time-to-interactive.

const HeavyChart = dynamic(() => import("@/components/dashboard/Chart"), {
  loading: () => <Skeleton />,
});

Next.js Image Component: Always use <Image /> from Next.js instead of raw <img>. Why: automatic WebP conversion, lazy loading, and prevents layout shifts from unspecified dimensions.

Avoid re-render triggers:

  • Do not update top-level state on every keypress in a localized text input.
  • Group related form fields into a single state object — not individual useState per field. Why: individual field states trigger a re-render per character typed.

Hydration Stability: Server-rendered HTML must match client-rendered output exactly. Common mismatch causes:

  • Using window or localStorage during server render — wrap in useEffect.
  • Rendering timestamps or random values differently on server vs client.

Puppeteer Visual QA: For catching layout bugs across viewports, write a Puppeteer script that spins up the dev server, navigates key views, takes screenshots across Mobile/Tablet/Desktop, and feeds them back to the AI for self-correction. This is the professional alternative to manual visual testing.

API Service Layer

All backend communication must go through services/ — never call fetch directly from a component file.

// services/invoiceService.ts
export const fetchInvoices = async (token: string) => {
  const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/v1/invoices`, {
    headers: { Authorization: `Bearer ${token}` },
  });
  if (!res.ok) throw new Error("Failed to fetch invoices");
  return res.json();
};

Why: centralizing API calls means one place to update base URLs, auth headers, and error handling — not hunting through 20 component files.

Decision Guide

Situation Correct action
Need same component in 2+ places Abstract into components/ui/ first
State needed by sibling components Lift to parent or use React Context
Component causes infinite re-render Check useEffect dependency array first
TypeScript throwing any errors Define a proper interface — do not suppress
Mobile layout is broken Sidebar must be a drawer; grid must stack — fix responsive classes
Slow initial page load Add dynamic imports for heavy components

Anti-Patterns

❌ Never do this ✅ Do this instead
Call DB directly from a React component Route all data through services/ API layer
Store JWT in localStorage Keep access token in React state; refresh in HttpOnly cookie
Use any type in TypeScript Define interfaces for every payload and model
Omit useEffect dependency array Always specify [] or exact deps
Hardcode hex in component className Map to CSS root variable in global.css
Shrink desktop sidebar on mobile Collapse sidebar to a drawer component
Use raw <img> tags Use Next.js <Image /> with explicit dimensions

Gotchas

  • Hydration errors in Next.js are almost always caused by server/client output mismatch — check for browser-only APIs (window, document, localStorage) running during SSR. Wrap them in useEffect.

  • useEffect with no dependency array runs on every render — this is almost never what you want and is a common source of infinite loops.

  • TypeScript's any type is a silent failure — it compiles fine and crashes at runtime. Treat any use of any as a bug, not a shortcut.

  • Grouping form fields into one state object reduces re-renders but requires spread syntax to update individual fields: setForm(prev => ({ ...prev, email: value })).


Handoff

Skill: frontend-engineering
Type: Reference
Trigger phrases covered: "build a component", "why is my state looping",
  "how should I structure this", "fix the mobile layout", "useEffect issue"
DO NOT TRIGGER for: backend routes, database schemas, server logic, deployment
Test prompts to verify:
  1. "Build a reusable Button component with Primary and Ghost variants"
     → Should trigger; component goes in components/ui/, CSS vars used, cursor:pointer set
  2. "My useEffect is causing an infinite loop, what's wrong?"
     → Should trigger; dependency array rules applied immediately
  3. "Write a MongoDB schema for invoices"
     → Should NOT trigger; database schema is backend work
Pass/fail rubric score: 5/5
Suggested next iteration: add SWR or React Query patterns if user's projects
  use server-state management heavily beyond basic useEffect fetching

Source: SKILL.md on GitHub

No third-party reports yet.

Signed by skilld at e0e2d0a. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated last month

README badge

README badge for mdzubair933/web-design-mastery-skills/frontend-engineering