Skip to content

Composition, not inheritance

UI libs receive behavior via props and slots — they do not pull from app context.

react-platform-composition-not-inheritance

Why it matters

Failure modes if this rule is ignored
StakeIf ignored
Hard to test
  • A component that inherits from context cannot be rendered alone in Storybook without faking the context.
Hard to change
  • Composition enables reuse without "variants" — one component, assembled differently per host. Inheritance forces a new variant for every new context.

How to fix

UI libs do not inherit behavior from context. They receive it — as props, as children, as render-props, as slots. The parent decides how to assemble; the child only knows how to render.

Examples

Bad
tsx
// libs/shared/ui-chat/src/lib/chat-panel.tsx
function ChatPanel() {
  const hostContext = useHostContext();
  const workspaceContext = useWorkspaceContext();
  return (
    <div>
      <ChatHeader title={hostContext?.siteName ?? workspaceContext?.workflowName} />
      <ChatMessages />
    </div>
  );
}
Good
tsx
// libs/shared/ui-chat/src/lib/chat-panel.tsx
export function ChatPanel({ header, children }: {
  header: ReactNode;
  children: ReactNode;
}) {
  return <div>{header}{children}</div>;
}

// libs/embedded-host/feature-chat/src/lib/host-chat.tsx
<ChatPanel header={<ChatHeader title={site.name} />}>
  <ChatMessages />
</ChatPanel>

Contribute

Released under the MIT License.

esc