Senior frontend
Skill tranhieutt/software_development_department/.claude/skills/senior-frontend
Software Development Department
npx -y skills add tranhieutt/software_development_department --skill senior-frontendAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Next.js App Router specific patterns — Server Components, Client Components boundary, parallel fetching, bundle analysis, a11y. Use ONLY for Next.js 13+ App Router projects. For generic React/Vue patterns, use `frontend-patterns` instead.
SKILL.md
4.9 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it
Senior Frontend
Critical rules (non-obvious)
- Always
returnin server components before client boundary — mixing async server + client state without boundaries causes hydration mismatches priorityon LCP images only — addingpriorityeverywhere defeats preload budgetsuse clientat the leaf, not the root — push client boundary as deep as possible to maximize RSC tree- Parallel data fetching in Server Components: use
Promise.all([...])at the page level, not sequential awaits - Bundle heavy deps:
moment(290KB) →dayjs(2KB);lodash→lodash-eswith tree-shaking;axios→ nativefetch
Next.js: server vs client boundary
// Server Component (default) — fetch directly, no hooks
async function ProductPage({ params }: { params: { id: string } }) {
const [product, reviews] = await Promise.all([ // parallel fetch
getProduct(params.id),
getReviews(params.id),
]);
return (
<div>
<h1>{product.name}</h1>
<Suspense fallback={<ReviewsSkeleton />}>
<Reviews productId={params.id} /> {/* can defer slow queries */}
</Suspense>
<AddToCartButton productId={product.id} /> {/* client boundary at leaf */}
</div>
);
}
// Client Component — only where interactivity needed
"use client";
function AddToCartButton({ productId }: { productId: string }) {
const [adding, setAdding] = useState(false);
return <button onClick={() => addToCart(productId)}>Add to Cart</button>;
}
Next.js: config essentials
// next.config.js
const nextConfig = {
images: {
remotePatterns: [{ hostname: "cdn.example.com" }],
formats: ["image/avif", "image/webp"],
},
experimental: {
optimizePackageImports: ["lucide-react", "@heroicons/react"], // tree-shake icon libs
},
};
Component: TypeScript patterns
// Generic list component
function List<T extends { id: string }>({ items, renderItem }: {
items: T[];
renderItem: (item: T) => React.ReactNode;
}) {
return <ul>{items.map(item => <li key={item.id}>{renderItem(item)}</li>)}</ul>;
}
// Props extending HTML element
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "primary" | "ghost" | "danger";
isLoading?: boolean;
}
export function Button({ variant = "primary", isLoading, children, ...props }: ButtonProps) {
return (
<button {...props} disabled={props.disabled || isLoading} aria-busy={isLoading}
className={cn("px-4 py-2 rounded font-medium focus-visible:ring-2",
variant === "primary" && "bg-blue-600 text-white hover:bg-blue-700",
variant === "danger" && "bg-red-600 text-white",
(props.disabled || isLoading) && "opacity-50 cursor-not-allowed"
)}>
{isLoading && <Spinner aria-hidden />}
{children}
</button>
);
}
Performance: bundle analysis
Common heavy deps to replace:
| Package | Size | Alternative |
|---|---|---|
| moment | 290KB | dayjs (2KB) or date-fns (12KB) |
| lodash | 71KB | lodash-es (tree-shakeable) |
| axios | 14KB | native fetch or ky (3KB) |
| @mui/material | Large | shadcn/ui or Radix UI |
# Analyze bundle
npx @next/bundle-analyzer # or
npx vite-bundle-visualizer
Accessibility essentials
// Skip link — place before main nav
<a href="#main-content" className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4">
Skip to main content
</a>
// Icon button — always label
<button type="button" aria-label="Close dialog" className="focus-visible:ring-2">
<XIcon aria-hidden="true" />
</button>
// Minimum contrast: 4.5:1 for text, 3:1 for UI components
Project structure (Next.js App Router)
app/
├── layout.tsx # Root layout: fonts, providers, metadata
├── page.tsx
├── (auth)/ # Route group — no URL segment
│ ├── login/page.tsx
│ └── register/page.tsx
└── api/
└── [route]/route.ts
components/
├── ui/ # Button, Input, Card (reusable primitives)
└── features/ # Domain-specific composites
hooks/ # useDebounce, useLocalStorage, useMediaQuery
lib/
├── utils.ts # cn(), formatDate()
└── api.ts # API client
types/ # Shared TypeScript types
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.
Gives 0 of the 12 instructions most design frontend skills give in ~1.1k tokens
Counted across 1,169 of the 1,878 authors here whose files we hold, read 2026-08-07
- Use CSS variables for color consistencyin 72 of 1169, across 23 files
- Commit to one bold aesthetic direction before codingin 72 of 1169, across 27 files
- Match implementation complexity to the aesthetic visionin 70 of 1169, across 20 files
- Add atmospheric background effects and texturesin 57 of 1169, across 9 files
- Use unexpected spatial compositions and layoutsin 56 of 1169, across 8 files
- Implement real working codein 55 of 1169, across 7 files
- Vary themes and aesthetics across different designsin 48 of 1169, across 7 files
- Launch chromium in headless modein 47 of 1169, across 4 files
- Close the browser when donein 47 of 1169, across 4 files
- Run provided scripts with help flag firstin 47 of 1169, across 4 files
- Wait for network idle statein 47 of 1169, across 4 files
- Use descriptive selectors for elementsin 47 of 1169, across 4 files
Said here and by no other author read
- return in server components before client boundary
- add priority to lcp images only
- push use client directive to leaf components
- fetch data in parallel using promise all
- replace heavy dependencies with lighter alternatives
- enable optimized package imports in next config
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.