Code style
Code style guide for JavaScript, TypeScript (Strict Mode), React 19+, and Tailwind CSS. Use this skill whenever writing, reviewing, or refactoring any JS/TS file, React component, or Tailwind UI. Trigger on: "how should I name this?", "is this clean?", "review my component", "refactor this", "best practices", any new function/hook/component creation, or any code that feels inconsistent. Apply proactively — don't wait to be asked.From its SKILL.md
npx -y skills add jjmendezrodriguez/jm-claude-plugin --skill code-styleAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
6.0 KB, as published. Nobody here has run it
Code Style — JS / TS / React / Tailwind
Staff Engineer standard: optimize for readability at scale, not cleverness.
1. Universal Rules (all files)
✅ Descriptive names in English
✅ One function = one responsibility
✅ Max ~25 lines per function — if longer, extract
✅ Comments explain WHY, not WHAT
✅ Linear flow: Validate → Process → Return
✅ Avoid deep nesting (max 2 levels)
✅ Consistent formatter (Prettier + ESLint — no exceptions)
2. Naming Conventions
| Element | Convention | Example |
|---|---|---|
| Functions / hooks | camelCase, verb | getUserData, useAuthSession |
| Variables / state | camelCase | isLoading, userData |
| Constants | UPPER_SNAKE_CASE | MAX_RETRIES, API_BASE_URL |
| Classes / Types | PascalCase | UserService, ApiResponse |
| React components | PascalCase | UserDashboard, LoginForm |
| Files (TS/JS) | kebab-case | user-service.ts, auth-hook.ts |
| Files (components) | PascalCase | UserCard.tsx, LoginForm.tsx |
Pick ONE convention per project. Enforce it via ESLint.
3. TypeScript Strict Mode
// tsconfig.json — non-negotiable
{
"strict": true, // enables all strict checks
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true
}
Rules:
- No
any— useunknown+ type guards if needed - Explicit return types on public functions
- Prefer
typeoverinterfaceunless extending - Use discriminated unions over optional fields
// ✅ Discriminated union — safe, exhaustive
type Result<T> =
| { status: "ok"; data: T }
| { status: "error"; message: string };
// ❌ Optional soup — ambiguous
type Result<T> = { data?: T; error?: string };
4. Function Documentation (JSDoc)
Required on: exported functions, hooks, service methods.
/**
* Fetches paginated users from the API.
*
* @param page - 1-based page number
* @param limit - Items per page (max 100)
* @returns Paginated user list
* @throws {NotFoundError} When page exceeds total
*
* @example
* const users = await getUsers(1, 20);
*/
export async function getUsers(page: number, limit: number): Promise<PaginatedResult<User>> {
// implementation
}
5. Code Flow
// ✅ GOOD — linear, fail-fast, readable
const processPayment = async (amount: number): Promise<PaymentResult> => {
if (amount <= 0) throw new ValidationError("Amount must be positive");
const result = await paymentService.charge(amount);
return result;
};
// ❌ BAD — nested ifs, scattered returns, no types
const processPayment = async (amount) => {
if (amount > 0) {
if (user.verified) {
if (balance >= amount) {
return await charge(amount);
} else { return null; }
}
}
return null;
};
Pattern: Validate → Process → Return. Always.
6. React 19+ Components
// ✅ Typed props, single responsibility, no logic leaking into JSX
type UserCardProps = {
userId: string;
onSelect: (id: string) => void;
};
export const UserCard = ({ userId, onSelect }: UserCardProps) => {
const { data, isLoading } = useUser(userId); // logic in hook
if (isLoading) return <Skeleton />;
return (
<article onClick={() => onSelect(userId)}>
<h2>{data.name}</h2>
</article>
);
};
Rules:
- Keep components under ~80 lines — extract sub-components if larger
- Logic → custom hooks. UI → component. Never mix.
- No inline functions in JSX props if they cause re-renders
- Co-locate:
UserCard.tsx,useUserCard.ts,UserCard.test.tsxin same folder
7. Tailwind CSS
// ✅ Readable: group by concern, use cn() for conditionals
import { cn } from "@/lib/utils";
const Button = ({ variant, disabled }: ButtonProps) => (
<button
className={cn(
"rounded-md px-4 py-2 text-sm font-medium transition-colors",
variant === "primary" && "bg-blue-600 text-white hover:bg-blue-700",
variant === "ghost" && "bg-transparent text-gray-700 hover:bg-gray-100",
disabled && "cursor-not-allowed opacity-50"
)}
>
Click
</button>
);
// ❌ BAD — unreadable wall of classes, no structure
<button className="rounded-md px-4 py-2 text-sm font-medium bg-blue-600 text-white hover:bg-blue-700 cursor-not-allowed opacity-50 transition-colors">
Rules:
- Use
cn()(clsx + tailwind-merge) for conditional classes — always - No arbitrary values unless design token doesn't exist (
[20px]→ use spacing scale) - Extract repeated class groups into a component or
@applyin global CSS (sparingly) - Mobile-first:
base → sm: → md: → lg:
8. Deep-Dive References
references/ holds extended guides:
| File | Contents |
|---|---|
tailwind-deep.md + references/ | Tailwind v4.1+ utilities, responsive patterns, dark mode, component variants |
typescript-advanced.md | Advanced TS: conditional types, mapped types, template literals, variance, branded types |
9. Quick Checklist (before PR)
[ ] No `any` in TypeScript
[ ] JSDoc on all exported functions
[ ] No function > 25 lines without justification
[ ] No nesting > 2 levels
[ ] Tailwind classes use cn() for conditionals
[ ] Component has single responsibility
[ ] Logic extracted to custom hook if >3 useState/useEffect
[ ] Files follow naming convention for the project