New Component
Scaffold a new UI component matching the project conventions.
/new-component<ComponentName> [props]Install to ~/.claude/commands/new-component.md
Scaffold a new UI component named in $ARGUMENTS, generated to match this repository's existing conventions exactly. Discover the conventions first by reading real neighbor components — never impose a structure the repo does not already use.
Scope
Read $ARGUMENTS as <ComponentName> [props]:
- The first token is the component name in the project's casing (e.g.
UserCard,user-card). Normalize it to whatever convention the codebase uses, not your own preference. - Any remaining tokens are a rough prop list —
title:string variant?:primary|secondary count:number onSelect:fn. Treat?as optional andfnas a callback. If props are vague, infer a minimal sensible interface and note your assumptions.
If $ARGUMENTS is empty, ask for the component name and its purpose before generating anything. Do not invent a component the user did not request.
Step 1 — Detect the project's conventions
Before writing a single line, find a representative existing component and study how it is built. This is the most important step — everything downstream mirrors what you find here.
# Find existing components to mirror (adapt globs to the repo)
fd -e tsx -e jsx -e vue -e svelte . src/components src/app 2>/dev/null | head -30
# Inspect the manifest for framework, test runner, and styling deps
cat package.jsonFrom a real neighbor file, extract and write down:
- Framework & file type — React
.tsx, Vue SFC.vue, Svelte.svelte, Solid, Angular. - File layout — one file per component vs. a folder (
Button/index.tsx,Button.tsx,Button.test.tsx,Button.stories.tsx). - Styling — Tailwind classes, CSS Modules,
styled-components, vanilla-extract, plain CSS. Note anycn()/clsxhelper and variant utility (cva,tv). - Prop typing —
interface Propsvs.type Props,React.FCvs. plain function,forwardRef, default exports vs. named. - Test / story patterns — the test framework (
vitest,jest,@testing-library), and whether stories use CSF, MDX, or none. - Imports & aliases — path aliases (
@/components), import ordering, and how shared primitives are imported.
NOTE
Pick the closest neighbor to what you are building (a card if scaffolding a card) and mirror it line for line — directory, naming, export style, and formatting. A component that looks hand-written by the team beats a "correct" one that fights the codebase.
Step 2 — Generate the component
Create the component file at the location and with the naming the codebase uses. The block below is illustrative — match the framework and style you found in Step 1, not this snippet.
import { cn } from "@/lib/utils";
interface UserCardProps {
title: string;
variant?: "primary" | "secondary";
count: number;
onSelect?: () => void;
}
export function UserCard({
title,
variant = "primary",
count,
onSelect,
}: UserCardProps) {
return (
<div
className={cn("rounded-lg border p-4", variant === "primary" && "bg-card")}
onClick={onSelect}
>
<h3>{title}</h3>
<span>{count}</span>
</div>
);
}- Reuse existing primitives and helpers (the local
cn(), sharedButton, design tokens) instead of reintroducing your own. - Keep the public prop surface minimal and typed; derive optionality from the
?markers in$ARGUMENTS. - Match the neighbor's export style (named vs. default) so existing import patterns keep working.
WARNING
Only create the files needed for this component. Do not edit unrelated files, restructure folders, add dependencies, or change shared config. If a missing helper or barrel export is required, flag it rather than silently introducing a new pattern.
Step 3 — Add types, test, and story
Generate the supporting files that the neighbor component has — no more, no fewer. If the project keeps types inline, keep them inline; if it ships a .test.tsx and a .stories.tsx alongside each component, produce both in the same folder.
// UserCard.test.tsx — mirror the project's test framework and queries
import { render, screen } from "@testing-library/react";
import { UserCard } from "./UserCard";
test("renders the title", () => {
render(<UserCard title="Ada" count={3} />);
expect(screen.getByText("Ada")).toBeInTheDocument();
});- Put each file exactly where the codebase puts it, and use its import aliases.
- Cover the rendered output and one prop-driven branch in the test; do not over-test scaffolding.
- If the repo has no tests or no stories, skip that artifact — do not introduce a tool the project does not use.
NOTE
If you add the component to a barrel file (index.ts) or registry, only do so when neighbors are exported the same way. Follow the existing export ordering.
Step 4 — Verify and report
Confirm the generated files fit the project before handing back.
# Adapt to the repo's commands
npm run lint
npx tsc --noEmit # or the project's typecheck/build command
# npm run build # heavier fallback if you need a full bundleReport concisely:
- Files created — each path, and the neighbor file each one was modeled on.
- Props — the resolved interface and any optionality or types you inferred.
- Conventions followed — framework, styling approach, export style, and test/story pattern matched.
- Follow-ups — anything intentionally skipped (no story because the repo has none) or a missing helper the user should wire up.
Related
- Frontend DeveloperUse this agent to build UI — responsive layouts, components, accessibility, and design-system work. Examples — implementing a Figma design, fixing a11y issues, building a reusable component.
- React SpecialistUse this agent for React architecture — hooks, state, performance, Server Components, and patterns. Examples — fixing re-render issues, designing component state, adopting RSC.
- Write TestsGenerate tests covering the happy path and edge cases for the given target.
- Add a Streaming LLM EndpointScaffold a token-streaming LLM endpoint — server-side streaming plus the client handler — so responses render incrementally instead of after a long wait.