frontend/building-components/SKILL.md
Build React components with TypeScript, composition patterns, and consistent structure.
npx skillsauth add 7a336e6e/skills building-componentsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
4 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Create well-typed, reusable React function components following composition-first patterns with co-located types, tests, and styles.
Co-locate the component, its types, tests, and barrel export in a single directory:
Button/
├── Button.tsx # Component implementation
├── Button.test.tsx # Tests
└── index.ts # Re-export: export { Button } from "./Button";
Always use interface for component props. Extend native HTML attributes when wrapping primitives:
import { forwardRef, type ButtonHTMLAttributes } from "react";
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "primary" | "secondary" | "ghost";
size?: "sm" | "md" | "lg";
isLoading?: boolean;
}
Use named function declarations. Forward refs on all primitives:
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ variant = "primary", size = "md", isLoading = false, children, className, ...rest }, ref) => {
const baseStyles = "inline-flex items-center justify-center rounded font-medium transition";
const variantStyles: Record<NonNullable<ButtonProps["variant"]>, string> = {
primary: "bg-blue-600 text-white hover:bg-blue-700",
secondary: "bg-gray-200 text-gray-900 hover:bg-gray-300",
ghost: "bg-transparent text-gray-700 hover:bg-gray-100",
};
const sizeStyles: Record<NonNullable<ButtonProps["size"]>, string> = {
sm: "px-3 py-1.5 text-sm",
md: "px-4 py-2 text-base",
lg: "px-6 py-3 text-lg",
};
return (
<button
ref={ref}
className={`${baseStyles} ${variantStyles[variant]} ${sizeStyles[size]} ${className ?? ""}`}
disabled={isLoading || rest.disabled}
{...rest}
>
{isLoading ? <span className="animate-spin mr-2">...</span> : null}
{children}
</button>
);
},
);
Button.displayName = "Button";
export { Button };
Prefer composing small components over adding many props to one component:
// Good: composable
<Card>
<Card.Header>
<Card.Title>Dashboard</Card.Title>
</Card.Header>
<Card.Body>{content}</Card.Body>
</Card>
// Avoid: prop-heavy
<Card title="Dashboard" headerAction={<Button />} body={content} footer={footer} />
| Category | Location | Purpose |
|-------------|---------------------------|--------------------------------------|
| Primitives | components/ui/ | Button, Input, Card, Modal |
| Composites | components/features/ | UserCard, InvoiceTable, SearchBar |
| Pages | pages/ | DashboardPage, SettingsPage |
Keep data fetching out of presentational components. Pass data through props:
// Page fetches, component renders
function UsersPage() {
const { data: users } = useQuery({ queryKey: ["users"], queryFn: fetchUsers });
return <UserList users={users ?? []} />;
}
// Pure presentational component
interface UserListProps {
users: User[];
}
function UserList({ users }: UserListProps) {
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
interfaceforwardRef on all primitive UI componentsany or unknown for prop typesA component directory containing:
ComponentName.tsx with typed props and implementationindex.ts barrel exportComponentName.test.tsx placeholder or full testsdevelopment
Implement features using the Red-Green-Refactor cycle to ensure testability and correctness from the start.
data-ai
Manage the `tasks.md` ledger with strict locking and collision avoidance protocols to allow multiple agents to work in parallel safely.
development
The git-workflow skill defines branching conventions, commit message formats, and pull request standards that all agents must follow for consistent version control.
development
The environment-config skill standardizes how agents manage environment variables, secrets, and application configuration across local development and deployed environments.