One of the most common tasks in a React project is creating reusable components that are flexible and easy to maintain.
In this post, I’ll share a quick and practical pattern to build typed, reusable components in React + TypeScript — keeping it simple and effective for real-world use.
✅ The Problem: Reusability + Type Safety
Imagine you need a button component that supports different variants (like primary
, secondary
), handles clicks, and accepts any content inside it. How would you type it properly?
Here’s a clean way and efficient way to do it:
💻 The Solution: Union Types + React Props
type ButtonProps = {
variant?: 'primary' | 'secondary';
onClick: () => void;
children: React.ReactNode;
};
export const Button = ({ variant = 'primary', onClick, children }: ButtonProps) => {
return (
<button className={`btn ${variant}`} onClick={onClick}>
{children}
</button>
);
};
⚙️ Why this works great?
-
variant
is defined as a union type ('primary' | 'secondary'
), making them type-safe and auto-completed by your editor. -
children
allows flexibility to pass any content (like icons or text). - Default value for variant simplifies usage.
- Easy to extend — just add more variants as needed.
🔑 Usage Example:
<Button onClick={() => console.log('Clicked!')}>
Click me
</Button>
<Button variant="secondary" onClick={() => alert('Secondary clicked')}>
Secondary Action
</Button>
💡 Pro Tip:
Want to add styled-components or CSS Modules? You can map variant
directly to class names or styled variants like this:
<Button variant="secondary" onClick={() => alert('Secondary Clicked!')}>
Secondary Action
</Button>
const StyledButton = styled.button<{ variant: 'primary' | 'secondary' }>`
background: ${({ variant }) => (variant === 'primary' ? 'blue' : 'gray')};
color: white;
padding: 10px 20px;
`;
This is a simple pattern to keep React components clean, flexible, and maintainable — something that can help any Front-End Developer in daily work.
👉 How do you handle reusable components in your projects? Share your approach in the comments! 👇
Top comments (0)