{
  "schemaVersion": "1.0",
  "item": {
    "slug": "composition-patterns",
    "name": "Frontend Composition Patterns",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/wpank/composition-patterns",
    "canonicalUrl": "https://clawhub.ai/wpank/composition-patterns",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/composition-patterns",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=composition-patterns",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "README.md",
      "SKILL.md",
      "rules/state-context-interface.md",
      "rules/state-decouple-implementation.md",
      "rules/state-lift-state.md",
      "rules/architecture-avoid-boolean-props.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "slug": "composition-patterns",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-03T11:42:13.897Z",
      "expiresAt": "2026-05-10T11:42:13.897Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=composition-patterns",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=composition-patterns",
        "contentDisposition": "attachment; filename=\"composition-patterns-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null,
        "slug": "composition-patterns"
      },
      "scope": "item",
      "summary": "Item download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this item.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/composition-patterns"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/composition-patterns",
    "agentPageUrl": "https://openagent3.xyz/skills/composition-patterns/agent",
    "manifestUrl": "https://openagent3.xyz/skills/composition-patterns/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/composition-patterns/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "React Composition Patterns",
        "body": "Build flexible, maintainable React components using compound components, context providers, and explicit variants. Avoid boolean prop proliferation."
      },
      {
        "title": "WHAT",
        "body": "Composition patterns that scale:\n\nCompound components with shared context\nState/actions/meta context interface for dependency injection\nExplicit variant components over boolean props\nLifted state in provider components\nChildren composition over render props"
      },
      {
        "title": "WHEN",
        "body": "Refactoring components with many boolean props\nBuilding reusable component libraries\nDesigning flexible component APIs\nCreating compound components (Card, Dialog, Form, etc.)\nComponents need shared state across sibling elements"
      },
      {
        "title": "KEYWORDS",
        "body": "composition, compound components, context, provider, boolean props, variants, react patterns, component architecture, render props, children\n\nSource: Vercel Engineering"
      },
      {
        "title": "OpenClaw / Moltbot / Clawbot",
        "body": "npx clawhub@latest install composition-patterns"
      },
      {
        "title": "Core Principle",
        "body": "Avoid boolean prop proliferation. Each boolean doubles possible states.\n\n// BAD: 4 booleans = 16 possible states\n<Composer isThread isDMThread isEditing isForwarding />\n\n// GOOD: Explicit variants, clear intent\n<ThreadComposer channelId=\"abc\" />\n<EditComposer messageId=\"xyz\" />"
      },
      {
        "title": "Pattern 1: Compound Components",
        "body": "Structure complex components with shared context. Consumers compose what they need.\n\nconst ComposerContext = createContext<ComposerContextValue | null>(null)\n\n// Provider handles state\nfunction ComposerProvider({ children, state, actions, meta }: ProviderProps) {\n  return (\n    <ComposerContext value={{ state, actions, meta }}>\n      {children}\n    </ComposerContext>\n  )\n}\n\n// Subcomponents access context\nfunction ComposerInput() {\n  const { state, actions: { update }, meta: { inputRef } } = use(ComposerContext)\n  return (\n    <TextInput\n      ref={inputRef}\n      value={state.input}\n      onChangeText={(text) => update(s => ({ ...s, input: text }))}\n    />\n  )\n}\n\nfunction ComposerSubmit() {\n  const { actions: { submit } } = use(ComposerContext)\n  return <Button onPress={submit}>Send</Button>\n}\n\n// Export as namespace\nconst Composer = {\n  Provider: ComposerProvider,\n  Frame: ComposerFrame,\n  Input: ComposerInput,\n  Submit: ComposerSubmit,\n  Header: ComposerHeader,\n  Footer: ComposerFooter,\n}\n\nUsage:\n\n<Composer.Provider state={state} actions={actions} meta={meta}>\n  <Composer.Frame>\n    <Composer.Header />\n    <Composer.Input />\n    <Composer.Footer>\n      <Composer.Formatting />\n      <Composer.Submit />\n    </Composer.Footer>\n  </Composer.Frame>\n</Composer.Provider>"
      },
      {
        "title": "Pattern 2: Generic Context Interface",
        "body": "Define a contract any provider can implement: state, actions, meta.\n\ninterface ComposerState {\n  input: string\n  attachments: Attachment[]\n  isSubmitting: boolean\n}\n\ninterface ComposerActions {\n  update: (updater: (state: ComposerState) => ComposerState) => void\n  submit: () => void\n}\n\ninterface ComposerMeta {\n  inputRef: React.RefObject<TextInput>\n}\n\ninterface ComposerContextValue {\n  state: ComposerState\n  actions: ComposerActions\n  meta: ComposerMeta\n}\n\nSame UI, different providers:\n\n// Local state provider\nfunction ForwardMessageProvider({ children }) {\n  const [state, setState] = useState(initialState)\n  return (\n    <ComposerContext value={{\n      state,\n      actions: { update: setState, submit: useForwardMessage() },\n      meta: { inputRef: useRef(null) },\n    }}>\n      {children}\n    </ComposerContext>\n  )\n}\n\n// Global synced state provider  \nfunction ChannelProvider({ channelId, children }) {\n  const { state, update, submit } = useGlobalChannel(channelId)\n  return (\n    <ComposerContext value={{\n      state,\n      actions: { update, submit },\n      meta: { inputRef: useRef(null) },\n    }}>\n      {children}\n    </ComposerContext>\n  )\n}\n\nBoth work with the same <Composer.Input /> component."
      },
      {
        "title": "Pattern 3: Explicit Variants",
        "body": "Create named components for each use case instead of boolean modes.\n\n// BAD: What does this render?\n<Composer\n  isThread\n  isEditing={false}\n  channelId=\"abc\"\n  showAttachments\n/>\n\n// GOOD: Self-documenting\n<ThreadComposer channelId=\"abc\" />\n\nImplementation:\n\nfunction ThreadComposer({ channelId }: { channelId: string }) {\n  return (\n    <ThreadProvider channelId={channelId}>\n      <Composer.Frame>\n        <Composer.Input />\n        <AlsoSendToChannelField channelId={channelId} />\n        <Composer.Footer>\n          <Composer.Formatting />\n          <Composer.Submit />\n        </Composer.Footer>\n      </Composer.Frame>\n    </ThreadProvider>\n  )\n}\n\nfunction EditComposer({ messageId }: { messageId: string }) {\n  return (\n    <EditProvider messageId={messageId}>\n      <Composer.Frame>\n        <Composer.Input />\n        <Composer.Footer>\n          <Composer.CancelEdit />\n          <Composer.SaveEdit />\n        </Composer.Footer>\n      </Composer.Frame>\n    </EditProvider>\n  )\n}"
      },
      {
        "title": "Pattern 4: Lifted State",
        "body": "Components outside the visual hierarchy can access state via provider.\n\nfunction ForwardMessageDialog() {\n  return (\n    <ForwardMessageProvider>\n      <Dialog>\n        {/* Composer UI */}\n        <Composer.Frame>\n          <Composer.Input placeholder=\"Add a message\" />\n          <Composer.Footer>\n            <Composer.Formatting />\n          </Composer.Footer>\n        </Composer.Frame>\n\n        {/* Preview OUTSIDE composer but reads its state */}\n        <MessagePreview />\n\n        {/* Actions OUTSIDE composer but can submit */}\n        <DialogActions>\n          <CancelButton />\n          <ForwardButton />\n        </DialogActions>\n      </Dialog>\n    </ForwardMessageProvider>\n  )\n}\n\n// Can access context despite being outside Composer.Frame\nfunction ForwardButton() {\n  const { actions: { submit } } = use(ComposerContext)\n  return <Button onPress={submit}>Forward</Button>\n}\n\nfunction MessagePreview() {\n  const { state } = use(ComposerContext)\n  return <Preview message={state.input} attachments={state.attachments} />\n}\n\nKey insight: Provider boundary matters, not visual nesting."
      },
      {
        "title": "Pattern 5: Children Over Render Props",
        "body": "Use children for composition, render props only when passing data.\n\n// BAD: Render props for structure\n<Composer\n  renderHeader={() => <CustomHeader />}\n  renderFooter={() => <Formatting />}\n  renderActions={() => <Submit />}\n/>\n\n// GOOD: Children for structure\n<Composer.Frame>\n  <CustomHeader />\n  <Composer.Input />\n  <Composer.Footer>\n    <Formatting />\n    <Submit />\n  </Composer.Footer>\n</Composer.Frame>\n\nWhen render props ARE appropriate:\n\n// Passing data to children\n<List\n  data={items}\n  renderItem={({ item, index }) => <Item item={item} index={index} />}\n/>"
      },
      {
        "title": "Pattern 6: Decouple State from UI",
        "body": "Only the provider knows how state is managed. UI consumes the interface.\n\n// BAD: UI coupled to state implementation\nfunction ChannelComposer({ channelId }) {\n  const state = useGlobalChannelState(channelId)  // Knows about global state\n  const { submit } = useChannelSync(channelId)    // Knows about sync\n  \n  return <Composer.Input value={state.input} onChange={...} />\n}\n\n// GOOD: State isolated in provider\nfunction ChannelProvider({ channelId, children }) {\n  const { state, update, submit } = useGlobalChannel(channelId)\n  \n  return (\n    <Composer.Provider\n      state={state}\n      actions={{ update, submit }}\n      meta={{ inputRef: useRef(null) }}\n    >\n      {children}\n    </Composer.Provider>\n  )\n}\n\n// UI only knows the interface\nfunction ChannelComposer() {\n  return (\n    <Composer.Frame>\n      <Composer.Input />  {/* Works with any provider */}\n      <Composer.Submit />\n    </Composer.Frame>\n  )\n}"
      },
      {
        "title": "Quick Reference",
        "body": "Anti-PatternSolutionBoolean propsExplicit variant componentsRender props for structureChildren compositionState in componentLift to providerCoupled to state implGeneric context interfaceMany conditional rendersCompose pieces explicitly"
      },
      {
        "title": "Files",
        "body": "rules/architecture-avoid-boolean-props.md - Detailed boolean prop guidance\nrules/architecture-compound-components.md - Compound component pattern\nrules/state-context-interface.md - Context interface design\nrules/state-decouple-implementation.md - State isolation\nrules/state-lift-state.md - Provider pattern\nrules/patterns-explicit-variants.md - Variant components\nrules/patterns-children-over-render-props.md - Composition over callbacks"
      },
      {
        "title": "NEVER",
        "body": "Add boolean props to customize behavior (use composition)\nCreate components with more than 2-3 boolean mode props\nCouple UI components to specific state implementations\nUse render props when children would work\nTrap state inside components when siblings need access"
      }
    ],
    "body": "React Composition Patterns\n\nBuild flexible, maintainable React components using compound components, context providers, and explicit variants. Avoid boolean prop proliferation.\n\nWHAT\n\nComposition patterns that scale:\n\nCompound components with shared context\nState/actions/meta context interface for dependency injection\nExplicit variant components over boolean props\nLifted state in provider components\nChildren composition over render props\nWHEN\nRefactoring components with many boolean props\nBuilding reusable component libraries\nDesigning flexible component APIs\nCreating compound components (Card, Dialog, Form, etc.)\nComponents need shared state across sibling elements\nKEYWORDS\n\ncomposition, compound components, context, provider, boolean props, variants, react patterns, component architecture, render props, children\n\nSource: Vercel Engineering\n\nInstallation\nOpenClaw / Moltbot / Clawbot\nnpx clawhub@latest install composition-patterns\n\nCore Principle\n\nAvoid boolean prop proliferation. Each boolean doubles possible states.\n\n// BAD: 4 booleans = 16 possible states\n<Composer isThread isDMThread isEditing isForwarding />\n\n// GOOD: Explicit variants, clear intent\n<ThreadComposer channelId=\"abc\" />\n<EditComposer messageId=\"xyz\" />\n\nPattern 1: Compound Components\n\nStructure complex components with shared context. Consumers compose what they need.\n\nconst ComposerContext = createContext<ComposerContextValue | null>(null)\n\n// Provider handles state\nfunction ComposerProvider({ children, state, actions, meta }: ProviderProps) {\n  return (\n    <ComposerContext value={{ state, actions, meta }}>\n      {children}\n    </ComposerContext>\n  )\n}\n\n// Subcomponents access context\nfunction ComposerInput() {\n  const { state, actions: { update }, meta: { inputRef } } = use(ComposerContext)\n  return (\n    <TextInput\n      ref={inputRef}\n      value={state.input}\n      onChangeText={(text) => update(s => ({ ...s, input: text }))}\n    />\n  )\n}\n\nfunction ComposerSubmit() {\n  const { actions: { submit } } = use(ComposerContext)\n  return <Button onPress={submit}>Send</Button>\n}\n\n// Export as namespace\nconst Composer = {\n  Provider: ComposerProvider,\n  Frame: ComposerFrame,\n  Input: ComposerInput,\n  Submit: ComposerSubmit,\n  Header: ComposerHeader,\n  Footer: ComposerFooter,\n}\n\n\nUsage:\n\n<Composer.Provider state={state} actions={actions} meta={meta}>\n  <Composer.Frame>\n    <Composer.Header />\n    <Composer.Input />\n    <Composer.Footer>\n      <Composer.Formatting />\n      <Composer.Submit />\n    </Composer.Footer>\n  </Composer.Frame>\n</Composer.Provider>\n\nPattern 2: Generic Context Interface\n\nDefine a contract any provider can implement: state, actions, meta.\n\ninterface ComposerState {\n  input: string\n  attachments: Attachment[]\n  isSubmitting: boolean\n}\n\ninterface ComposerActions {\n  update: (updater: (state: ComposerState) => ComposerState) => void\n  submit: () => void\n}\n\ninterface ComposerMeta {\n  inputRef: React.RefObject<TextInput>\n}\n\ninterface ComposerContextValue {\n  state: ComposerState\n  actions: ComposerActions\n  meta: ComposerMeta\n}\n\n\nSame UI, different providers:\n\n// Local state provider\nfunction ForwardMessageProvider({ children }) {\n  const [state, setState] = useState(initialState)\n  return (\n    <ComposerContext value={{\n      state,\n      actions: { update: setState, submit: useForwardMessage() },\n      meta: { inputRef: useRef(null) },\n    }}>\n      {children}\n    </ComposerContext>\n  )\n}\n\n// Global synced state provider  \nfunction ChannelProvider({ channelId, children }) {\n  const { state, update, submit } = useGlobalChannel(channelId)\n  return (\n    <ComposerContext value={{\n      state,\n      actions: { update, submit },\n      meta: { inputRef: useRef(null) },\n    }}>\n      {children}\n    </ComposerContext>\n  )\n}\n\n\nBoth work with the same <Composer.Input /> component.\n\nPattern 3: Explicit Variants\n\nCreate named components for each use case instead of boolean modes.\n\n// BAD: What does this render?\n<Composer\n  isThread\n  isEditing={false}\n  channelId=\"abc\"\n  showAttachments\n/>\n\n// GOOD: Self-documenting\n<ThreadComposer channelId=\"abc\" />\n\n\nImplementation:\n\nfunction ThreadComposer({ channelId }: { channelId: string }) {\n  return (\n    <ThreadProvider channelId={channelId}>\n      <Composer.Frame>\n        <Composer.Input />\n        <AlsoSendToChannelField channelId={channelId} />\n        <Composer.Footer>\n          <Composer.Formatting />\n          <Composer.Submit />\n        </Composer.Footer>\n      </Composer.Frame>\n    </ThreadProvider>\n  )\n}\n\nfunction EditComposer({ messageId }: { messageId: string }) {\n  return (\n    <EditProvider messageId={messageId}>\n      <Composer.Frame>\n        <Composer.Input />\n        <Composer.Footer>\n          <Composer.CancelEdit />\n          <Composer.SaveEdit />\n        </Composer.Footer>\n      </Composer.Frame>\n    </EditProvider>\n  )\n}\n\nPattern 4: Lifted State\n\nComponents outside the visual hierarchy can access state via provider.\n\nfunction ForwardMessageDialog() {\n  return (\n    <ForwardMessageProvider>\n      <Dialog>\n        {/* Composer UI */}\n        <Composer.Frame>\n          <Composer.Input placeholder=\"Add a message\" />\n          <Composer.Footer>\n            <Composer.Formatting />\n          </Composer.Footer>\n        </Composer.Frame>\n\n        {/* Preview OUTSIDE composer but reads its state */}\n        <MessagePreview />\n\n        {/* Actions OUTSIDE composer but can submit */}\n        <DialogActions>\n          <CancelButton />\n          <ForwardButton />\n        </DialogActions>\n      </Dialog>\n    </ForwardMessageProvider>\n  )\n}\n\n// Can access context despite being outside Composer.Frame\nfunction ForwardButton() {\n  const { actions: { submit } } = use(ComposerContext)\n  return <Button onPress={submit}>Forward</Button>\n}\n\nfunction MessagePreview() {\n  const { state } = use(ComposerContext)\n  return <Preview message={state.input} attachments={state.attachments} />\n}\n\n\nKey insight: Provider boundary matters, not visual nesting.\n\nPattern 5: Children Over Render Props\n\nUse children for composition, render props only when passing data.\n\n// BAD: Render props for structure\n<Composer\n  renderHeader={() => <CustomHeader />}\n  renderFooter={() => <Formatting />}\n  renderActions={() => <Submit />}\n/>\n\n// GOOD: Children for structure\n<Composer.Frame>\n  <CustomHeader />\n  <Composer.Input />\n  <Composer.Footer>\n    <Formatting />\n    <Submit />\n  </Composer.Footer>\n</Composer.Frame>\n\n\nWhen render props ARE appropriate:\n\n// Passing data to children\n<List\n  data={items}\n  renderItem={({ item, index }) => <Item item={item} index={index} />}\n/>\n\nPattern 6: Decouple State from UI\n\nOnly the provider knows how state is managed. UI consumes the interface.\n\n// BAD: UI coupled to state implementation\nfunction ChannelComposer({ channelId }) {\n  const state = useGlobalChannelState(channelId)  // Knows about global state\n  const { submit } = useChannelSync(channelId)    // Knows about sync\n  \n  return <Composer.Input value={state.input} onChange={...} />\n}\n\n// GOOD: State isolated in provider\nfunction ChannelProvider({ channelId, children }) {\n  const { state, update, submit } = useGlobalChannel(channelId)\n  \n  return (\n    <Composer.Provider\n      state={state}\n      actions={{ update, submit }}\n      meta={{ inputRef: useRef(null) }}\n    >\n      {children}\n    </Composer.Provider>\n  )\n}\n\n// UI only knows the interface\nfunction ChannelComposer() {\n  return (\n    <Composer.Frame>\n      <Composer.Input />  {/* Works with any provider */}\n      <Composer.Submit />\n    </Composer.Frame>\n  )\n}\n\nQuick Reference\nAnti-Pattern\tSolution\nBoolean props\tExplicit variant components\nRender props for structure\tChildren composition\nState in component\tLift to provider\nCoupled to state impl\tGeneric context interface\nMany conditional renders\tCompose pieces explicitly\nFiles\nrules/architecture-avoid-boolean-props.md - Detailed boolean prop guidance\nrules/architecture-compound-components.md - Compound component pattern\nrules/state-context-interface.md - Context interface design\nrules/state-decouple-implementation.md - State isolation\nrules/state-lift-state.md - Provider pattern\nrules/patterns-explicit-variants.md - Variant components\nrules/patterns-children-over-render-props.md - Composition over callbacks\nNEVER\nAdd boolean props to customize behavior (use composition)\nCreate components with more than 2-3 boolean mode props\nCouple UI components to specific state implementations\nUse render props when children would work\nTrap state inside components when siblings need access"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/wpank/composition-patterns",
    "publisherUrl": "https://clawhub.ai/wpank/composition-patterns",
    "owner": "wpank",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/composition-patterns",
    "downloadUrl": "https://openagent3.xyz/downloads/composition-patterns",
    "agentUrl": "https://openagent3.xyz/skills/composition-patterns/agent",
    "manifestUrl": "https://openagent3.xyz/skills/composition-patterns/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/composition-patterns/agent.md"
  }
}