React component design
Skill KraitDev/skiLL.Md/skills/frontend/react-component-design
skiLL.Md is a structured, open-source collection of reusable, self-contained markdown modules that describe how to perform specific software engineering tasks.
npx -y skills add KraitDev/skiLL.Md --skill react-component-designAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 6 stars6 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.
What its author says it does
Copied from the file, not written here
When building or refactoring React UI components to ensure reusability and maintainability.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
6.6 KB, as published. Nobody here has run it
React Component Design
Purpose
React components MUST be pure, composable, and reusable abstractions. This skill enforces TypeScript-first design, separation of concerns, and deterministic rendering to ensure maintainable, testable UI code that works reliably across different contexts.
When to use
- Building a new UI element from scratch
- Refactoring a large, monolithic React component
- Extracting shared UI patterns into a component library
- Adding new features to an existing component hierarchy
- Preparing components for cross-team reuse
When NOT to use
- Styling implementation details (use DOM Security Hardening skill instead)
- State management architecture decisions (use State Management Patterns skill)
- Performance optimization via memo/useMemo (handle at call site, not in component)
Inputs required
- Existing React codebase with TypeScript
- Clear understanding of component's single responsibility
- Props interface definition (before implementation)
Workflow
- Define the API: Write the TypeScript interface for props BEFORE the component body. This clarifies the contract.
- Verify Props: Ensure props contain ONLY what the component needs—no unnecessary inherited types.
- Isolate Logic: Extract all complex state and side-effects into custom hooks (NEVER in component body).
- Render JSX: Build static JSX structure based solely on props and hook return values.
- Apply Styles: Use CSS classes via
classNameprop. NEVER use inlinestyle={{...}}. - Export Type: Export both the component AND its Props interface for consumers.
- Verify Size: Confirm file does NOT exceed 150 lines. If it does, extract sub-components.
Rules
- MUST be a pure function: identical props = identical output
- MUST export a strictly typed TypeScript interface named
[ComponentName]Props - MUST NOT exceed 150 lines per file (extract sub-components if larger)
- MUST NOT use inline styles (
style={{...}}) - MUST NOT drill props more than 2 levels deep
- MUST NOT fetch data directly (use hooks or parent component)
- MUST support
classNameprop for customization
Anti-patterns
- Prop Drilling: Passing props down more than 2 levels deep (use Context, composition, or compound components)
- Inline Styles: Using
style={{...}}objects instead of CSS classes - God Components: Handling data fetching, business logic, and UI rendering in one file
- State in Props: Copying prop values into local state with
useState(props.val) - Implicit Dependencies: Accessing globals or services without prop parameters
- Class Components: Using class components instead of functional components with hooks
Failure conditions
- Component file exceeds 200 lines
- Props interface is not exported
- Component performs side effects without useEffect
- More than 2 levels of prop drilling detected
Validation checklist
- Props interface is explicitly exported and named
[ComponentName]Props - Component is a pure function with no render-time side effects
- No inline
style={{...}}objects anywhere - No prop drilling beyond 2 levels
- File is ≤ 150 lines
- All complex logic is extracted to custom hooks
- Component supports
classNameprop for customization - TypeScript types are strict (no
any) - No direct API/data fetching in component body
Output format
- File count: 1 primary
.tsxfile (+ additional files if refactored) - Exports: One default export (component) + named export for Props interface
- Structure: Props interface → Component function → Export both
- Styling: CSS classes only, no inline styles
- Size: ≤ 150 lines per component file
Security considerations
- Components do NOT execute arbitrary user input; text content is always escaped
- Props are never used in DOM insertion without sanitization
- Event handlers are never created from strings or user input
- No use of
dangerouslySetInnerHTML(violates DOM Security Hardening)
Agent execution notes
- Agent MAY: Create new components, refactor large components, add TypeScript interfaces
- Agent MUST NEVER: Add inline styles, drill props beyond 2 levels, add data fetching to component
- Agent MUST ASK: Before exceeding 150 lines, before changing prop contracts
- Agent MUST VALIDATE: All TypeScript is strict, no prop drilling, component is pure functional
Example
❌ Anti-pattern (Prop drilling, inline styles, state mirroring):
// Bad: mirrors props, inline styles, multiple responsibilities
export const Modal = ({ title, onClose, userId, userName, isOpen }) => {
const [name, setName] = useState(userName); // ANTI-PATTERN: state from props
return (
<div style={{ position: 'fixed', top: 0 }} onClick={onClose}>
<h1>{title}</h1>
<input value={name} onChange={(e) => setName(e.target.value)} />
<UserProfile userId={userId} name={name} /> {/* 2 levels */}
</div>
);
};
export const UserProfile = ({ userId, name }) => {
return <UserBio userId={userId} name={name} />; {/* 3 levels: VIOLATION */}
};
✅ Correct pattern (Pure, CSS classes, no drilling):
interface ModalProps {
title: string;
onClose: () => void;
isOpen: boolean;
children: React.ReactNode;
}
export const Modal = ({ title, onClose, isOpen, children }: ModalProps) => {
if (!isOpen) return null;
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content">
<h1>{title}</h1>
{children}
</div>
</div>
);
};
interface UserProfileProps {
userId: string;
}
export const UserProfile = ({ userId }: UserProfileProps) => {
const user = useUser(userId); // Use hook, not props
return (
<div>
<h2>{user?.name}</h2>
<p>{user?.bio}</p>
</div>
);
};