Stop writing prompts that sound like a job description. "Create a React component" gets you a generic <div> with a useState hook and a comment that says "handle logic here." That's not a component, that's a skeleton with a shrug.
React Component Prompts solve this by forcing the LLM to define the contract before it writes a single line of JSX. These templates work reliably with Claude, GPT-4, Gemini, and DeepSeek — I've used all four, and the same structural rigor applies.
The difference isn't the model. It's the constraints you feed it.
Why Generic Prompts Fail Here
The default failure mode is underspecification. You say "build a dropdown," and the LLM makes assumptions about styling, accessibility, keyboard navigation, and state management. Those assumptions rarely match your codebase.
The second failure mode is overspecification. You paste your entire design system into the prompt, and the LLM spends its context window trying to parse your CSS variables instead of writing the component.
Generic prompts fail because they don't separate what from how. A good React Component Prompt forces the model to ask the right questions before it answers them.
Template 1: The Contract-First Component
Build a React component called [ComponentName] that does [core function].
Requirements:
- Props interface: [list exact prop names and types]
- State: [describe what state is internal vs. lifted to parent]
- Event handlers: [list the events that must be handled and their side effects]
- Accessibility: [WCAG requirements, e.g., aria-labels, focus management]
- Styling: [CSS modules / styled-components / Tailwind / none]
Constraints:
- Do not add props beyond the interface above.
- Use [useCallback/useMemo] only where profiling shows a need.
- Return null if [edge case condition].
Output format:
1. TypeScript interface
2. Component code
3. Brief notes on why you chose this state shape
What each placeholder means:
[ComponentName]— be specific. "UserAvatar" beats "Avatar" because it implies context.[core function]— the single responsibility. If it needs an "and," split it into two components.[list exact prop names and types]— this is the contract. The LLM will follow it literally.[edge case condition]— this prevents the model from adding defensive checks that bloat the code.
Template 2: The Behavior-Driven Component
Write a React component called [ComponentName] that passes these tests:
Given [initial state],
When [user action],
Then [expected UI change].
Given [different state],
When [async operation resolves],
Then [expected UI change with loading/error states].
Rules:
- Use [state management approach: useState/useReducer/context].
- Handle [specific edge case] without breaking [existing behavior].
- The component must be testable with [testing library] — no mocking internal functions.
- Export the component and its types from the same file.
Do not write tests. Write the component that would pass them.
This template works because it inverts the usual flow. Instead of describing the component, you describe the observable behavior. The LLM has to design the internals to match.
Template 3: The Refactor-With-Constraints Prompt
Refactor the existing component [ComponentName] to fix [specific issue].
Current code:
[Paste the component code here]
The problem:
[Describe the bug or performance issue with concrete symptoms]
Constraints:
- Keep the public props interface identical.
- Do not introduce new dependencies.
- Must preserve [specific behavior that's working correctly].
- The refactored version must be under [N] lines.
After the refactor, list:
1. What you changed and why
2. What you deliberately left alone
3. Any trade-offs you made
If you cannot fix [specific issue] within these constraints, explain why instead of writing code.
This is the hardest template because it requires the LLM to restrain itself. The "explain why instead of writing code" clause is critical — it prevents the model from producing a confident but broken refactor.
How to Adapt These for Your Own Codebase
Generic templates work. Adapted templates stick.
First, replace the styling placeholder with your actual stack. If you use Tailwind, say "Tailwind classes only, no custom CSS." If you use CSS Modules, say "import styles from './Component.module.css'."
Second, add your linting rules to the constraints. "No any types. No inline styles. No default exports." The LLM will follow these if they're explicit.
Third, paste one example of an existing component you like. Not the whole file — just the pattern. Say "Match the prop naming convention in this example: [paste 5 lines]."
Fourth, for internal linking, check suhailroushan.com for component patterns I've published — they're a good reference baseline.
Do These Prompts Work With Any LLM?
Yes, but with a caveat. Claude follows the contract-first template most literally. GPT-4 handles the behavior-driven template best because it's strong at test reasoning. Gemini and DeepSeek work fine on all three, but they occasionally ignore the "do not add props" constraint — you'll need to verify the interface matches.
The templates are model-agnostic because they constrain the output shape, not the model's internal reasoning. Every LLM can follow a bulleted list of requirements.
The one adjustment that improves these prompts the most: add a single example of the expected output format. Paste a 10-line snippet of what the final component should look like structurally. It anchors the model's output better than any amount of instruction text.