djankies

composing-components

Teaches component composition patterns in React 19 including children prop, compound components, and render props. Use when designing component APIs, creating reusable components, or avoiding prop drilling.

djankies 0 Updated 9mo ago
GitHub

Install

npx skillscat add djankies/claude-configs/composing-components

Install via the SkillsCat registry.

About this skill

This skill teaches React 19 component composition patterns such as children props, compound components, and render props, enabling developers to build reusable, flexible interfaces without prop drilling. It is used when designing component APIs or creating coordinated UI elements like tabs or accordions.

SKILL.md

Component Composition Patterns

This skill teaches you how to compose components effectively using React 19 patterns. This skill activates when:
  • Designing reusable component APIs
  • Need to avoid prop drilling
  • Creating compound components (Tabs, Accordion, etc.)
  • Building flexible, composable interfaces
  • Choosing between composition patterns
React 19 supports multiple composition patterns:
  1. Children Prop - Simplest composition, pass components as children
  2. Compound Components - Components that work together (Context-based)
  3. Render Props - Functions as children for flexibility
  4. Composition over Props - Prefer slots over configuration props

When to Use:

  • Children prop: Simple containment
  • Compound components: Coordinated behavior (tabs, accordions)
  • Render props: Custom rendering logic
  • Slots: Multiple insertion points
## Pattern 1: Children Prop
function Card({ children, header, footer }) {
  return (
    <div className="card">
      {header && <div className="header">{header}</div>}
      <div className="body">{children}</div>
      {footer && <div className="footer">{footer}</div>}
    </div>
  );
}

<Card header={<h2>Title</h2>} footer={<button>Action</button>}>
  <p>Card content goes here</p>
</Card>;

Pattern 2: Compound Components

import { createContext, use } from 'react';

const TabsContext = createContext(null);

export function Tabs({ children, defaultTab }) {
  const [activeTab, setActiveTab] = useState(defaultTab);

  return (
    <TabsContext value={{ activeTab, setActiveTab }}>
      <div className="tabs">{children}</div>
    </TabsContext>
  );
}

export function TabList({ children }) {
  return <div className="tab-list">{children}</div>;
}

export function Tab({ id, children }) {
  const { activeTab, setActiveTab } = use(TabsContext);

  return (
    <button className={activeTab === id ? 'active' : ''} onClick={() => setActiveTab(id)}>
      {children}
    </button>
  );
}

export function TabPanel({ id, children }) {
  const { activeTab } = use(TabsContext);

  if (activeTab !== id) return null;

  return <div className="tab-panel">{children}</div>;
}

Usage:

<Tabs defaultTab="profile">
  <TabList>
    <Tab id="profile">Profile</Tab>
    <Tab id="settings">Settings</Tab>
  </TabList>

  <TabPanel id="profile">
    <Profile />
  </TabPanel>

  <TabPanel id="settings">
    <Settings />
  </TabPanel>
</Tabs>

Pattern 3: Render Props

function DataProvider({ render, endpoint }) {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch(endpoint)
      .then((res) => res.json())
      .then(setData);
  }, [endpoint]);

  return render({ data, loading: !data });
}

<DataProvider
  endpoint="/api/users"
  render={({ data, loading }) => (loading ? <Spinner /> : <UserList users={data} />)}
/>;
## Example: Modal with Composition
function Modal({ children, isOpen, onClose }) {
  if (!isOpen) return null;

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal" onClick={(e) => e.stopPropagation()}>
        {children}
      </div>
    </div>
  );
}

function ModalHeader({ children }) {
  return <div className="modal-header">{children}</div>;
}

function ModalBody({ children }) {
  return <div className="modal-body">{children}</div>;
}

function ModalFooter({ children }) {
  return <div className="modal-footer">{children}</div>;
}

Modal.Header = ModalHeader;
Modal.Body = ModalBody;
Modal.Footer = ModalFooter;

Usage:

<Modal isOpen={showModal} onClose={() => setShowModal(false)}>
  <Modal.Header>
    <h2>Confirm Action</h2>
  </Modal.Header>

  <Modal.Body>
    <p>Are you sure you want to proceed?</p>
  </Modal.Body>

  <Modal.Footer>
    <button onClick={() => setShowModal(false)}>Cancel</button>
    <button onClick={handleConfirm}>Confirm</button>
  </Modal.Footer>
</Modal>

For comprehensive composition patterns, see: research/react-19-comprehensive.md lines 1263-1293.

## MUST - Use `use()` API for Context in React 19 (can be conditional) - Keep compound components cohesive - Document required child components

SHOULD

  • Prefer composition over complex prop APIs
  • Use Context for compound component state
  • Provide good component names for debugging

NEVER

  • Over-engineer simple components
  • Use Context for non-coordinated components
  • Forget to handle edge cases (missing children, etc.)