Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
ReactNext.jsJune 21, 20264 min read

React composition patterns: Escaping Props Hell with Slots

React composition and inversion of control help you escape props hell. Learn how to use React slots to build flexible, maintainable UI components.

ReactComponent DesignFrontend EngineeringWeb DevelopmentTypeScriptNext.jsTutorial
A vintage-style sign with the words 'HELL YES' hanging indoors, offering a motivational and rustic vibe.

We’ve all been there: staring at a component with twenty-five props, half of which are just being passed down to a child three levels deep. Last month, I spent about two days refactoring a dashboard widget that had become a "God component" because I kept adding flags like showTitle, showIcon, isCompact, and hasBorder. It was a nightmare to maintain.

If you’re drowning in prop drilling, you’re likely fighting the architecture instead of working with it. By mastering React composition, you can stop passing data through middleman components and start injecting functionality where it actually belongs.

Understanding the "Props Hell" Problem

When you build components that try to do everything, you lose the ability to compose them. If your Card component needs to know exactly what icon to render, what header text to display, and whether to render a specific button based on a complex user permission, it becomes brittle.

We first tried solving this with a massive configuration object. It broke as soon as we needed a slightly different version of the card in the settings page. That’s when we pivoted to component design patterns that focus on inversion of control.

Leveraging React Slots for Flexibility

Coding on a laptop outdoors, showcasing a rooftop urban lifestyle in Surat, India.

The most effective way to escape this mess is by using React slots. Instead of passing data into a component, you pass the components themselves. This is a form of inversion of control where the parent decides what gets rendered in specific "slots" of the child.

Think of it like a Layout component. Instead of passing a title string, you pass a component that represents the header.

JSX
// The "Slot" pattern in action
function Card({ header, children, footer }) {
  return (
    <div className="card">
      {header && <header>{header}</header>}
      <main>{children}</main>
      {footer && <footer>{footer}</footer>}
    </div>
  );
}

// Usage
<Card 
  header={<DashboardHeader title="Analytics" />}
  footer={<Button onClick={save}>Save Changes</Button>}
>
  <ChartData />
</Card>

This approach is much cleaner than passing booleans and strings. It’s exactly how React composition and the children prop for scalable UI libraries should be handled to keep your components decoupled.

Why Inversion of Control Matters

By letting the parent component define the content, you make your UI primitives "dumb." A dumb component is easy to test and reuse. If you’re struggling with component boundaries as your team grows, you should also look into Component architecture that survives a growing team in Next.js to ensure your file structure supports this kind of modularity.

When you use inversion of control, you aren't just passing functions or components; you’re passing responsibility. The Card doesn't need to know how to fetch data or handle permissions; it only knows how to position the elements you give it.

Refactoring Strategy

If you're currently stuck in props hell, don't try to rewrite everything in one go. Here’s how I usually approach a refactor:

  1. Identify the "Config" Props: Look for props that are purely for layout or conditional rendering (e.g., showButton, variant="primary").
  2. Extract the Logic: If a component contains heavy logic, consider using the Next.js App Router Data Provider Pattern for Clean Architecture to move the heavy lifting out of the view layer.
  3. Replace with Slots: Swap the configuration props for ReactNode props.
  4. Test the Compose-ability: Try rendering the component in two different contexts. If it works in both without adding new props, you've succeeded.

Frequently Asked Questions

Is there a performance penalty for passing components as props?

In most cases, no. React is highly optimized for this. The biggest risk is unnecessary re-renders if you define components inline inside the parent's render cycle. If you notice performance dips, use useMemo or define your slot components outside the parent component.

When should I stop using slots?

If you find yourself creating a component that requires five or six different slots just to render one view, you might be over-composing. Sometimes, a dedicated, specific component is better than a generic, overly-slotted one. Trust your gut—if the code feels like a puzzle, you’ve gone too far.

How does this affect type safety?

If you're using TypeScript, it actually makes things better. You can define your props as header?: React.ReactNode. It’s much more flexible than a union of strings or objects.

Final Thoughts

I’m still experimenting with how far to push this pattern. Sometimes I find myself creating "compound components" (like <Select.Option />) instead of slots, which feels cleaner for highly interconnected UI elements.

Composition isn't a silver bullet, but it’s the best tool I’ve found to keep my code from turning into a pile of spaghetti. Don't feel like you have to get it perfect on the first try. Start by replacing one boolean prop with a slot, and see how much easier your life becomes.

Back to Blog

Similar Posts

Close-up of JavaScript code on a laptop screen, showcasing programming in progress.
ReactNext.jsJune 20, 20264 min read

React State Management: How to Lift State Up Effectively

React state management gets easier when you learn how to lift state up. Discover how to sync sibling components and build a predictable data flow today.

Read more
Coding on a laptop outdoors, showcasing a rooftop urban lifestyle in Surat, India.
ReactNext.jsJune 21, 20264 min read

React Server Components vs Client Components in Next.js

React Server Components vs Client Components: Learn how to manage the Next.js network boundary, optimize your frontend architecture, and boost performance.

Read more
Closeup of many cables with blue wires plugged in modern switch with similar adapters on blurred background in modern studio
ReactNext.jsJune 21, 20264 min read

Next.js App Router Data Provider Pattern for Clean Architecture

Master the Next.js App Router Data Provider pattern to decouple fetching from UI. Learn to inject data into React Server Components for cleaner, testable code.

Read more