Skip to main content

component-composition

Guides creation of CloudBeaver React components through children, slots, compound parts, and specialized components. Use when creating React components, designing their props, or choosing how callers supply content, actions, and layout regions.

Source facts

Repository
dbeaver/cloudbeaver
Last source activity
October 27, 2026 at 08:37
Detected SKILL.md language
English
Stars
5,209
Forks
574

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
2 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
component-composition
description
Guides creation of CloudBeaver React components through children, slots, compound parts, and specialized components. Use when creating React components, designing their props, or choosing how callers supply content, actions, and layout regions.
# Component composition Keep layout and behavior with the component; let its caller supply finished pieces of UI. Design the interface around the component's own responsibilities. Let callers compose content and actions instead of configuring nested UI through data, flags, and callbacks. Components must have no more than **five props**, excluding `children` and UI slots. If an interface exceeds this limit, use composition to move UI regions and their configuration to the caller. Only genuine UI slots are exempt; renaming a configuration prop does not make it a slot. ## Sort every prop first | A prop that… | Belongs… | | --- | --- | | Drives the component's own behavior (`value`, `open`, `onChange`, `disabled`) | On that component | | Picks a look for the whole component (`size`, `variant`) | On the root | | Fills one region (`title`, `description`, `icon`) | In `children`, a slot, or a part | | Configures a nested element (`actionLabel`, `onAction`, `actionDisabled`, `actionClassName`) | On the element rendered by the caller | | Selects substantially different markup or interaction (`inline`, `mode="drawer"`) | In a separate component sharing lower-level parts | | Changes the rendered element (`as`, `tag`, `href`, `render`) | On the underlying primitive, using its supported API | Keep native DOM props, accessibility attributes, refs, and controlled-state contracts intact. A boolean that changes a class is not automatically a second component. Domain data also belongs on a feature component that actually owns its behavior; do not turn every domain value into JSX. ## Choose the simplest pattern 1. **Children** for the main content. Start here. 2. **Slots** for a small, fixed set of regions. Type `<role>Slot` as `ReactNode`; place the value without inspecting it. Prefer `actionsSlot={<ConnectButton connection={connection} />}` to a label, visibility flag, disabled flag, and callback. Follow an existing local slot name when present. 3. **Render props** only when content needs state owned by the component. Expose a minimal typed argument, not the component's full store or internal implementation. 4. **Compound parts** when callers vary the presence, order, or configuration of regions. Reuse existing parts before introducing new wrappers. 5. **Separate components** when a mode selects another layout or interaction contract. Share parts underneath; keep small visual variants on the root. 6. **Wrap and specialize** an existing primitive when only defaults or feature wiring differ. Preserve its native and accessibility behavior instead of re-describing its API. Choose a more structured pattern only when it reduces what real callers have to know. Bundling props in `options`, renaming configuration to `xSlot`, or splitting internals while keeping the same prop-heavy interface does not transfer ownership. ## Compound parts - Name parts after their root and role: `ConnectionSummaryContent`, `ConnectionSummaryActions`. Use roles such as `Header`, `Title`, `Description`, `Content`, `Footer`, `Actions`, `Media`, `Icon`, `Group`, `Item`, `Separator`, `Trigger`, and `Label` only where they have a job. - A simple layout part renders one semantic element, accepts that element's props, merges `className`, and forwards the remaining props and refs according to the local primitive's API. Zero to two custom props is a useful heuristic, not a limit for headless primitives or controls. - Keep layout parts optional and let CSS adapt to their presence. Do not add `hasAction` or inspect, clone, or identify children to discover the layout. Semantic requirements still apply: a dialog needs an accessible name, and interactive parts need their provider and relationships. - Keep whole-component appearance on the root. Use existing classes or `data-*` attributes and scoped CSS selectors for parts; do not add context merely to distribute size or spacing. - Reuse the headless primitive's context/store for shared interactions. Add a local typed context only for behavior state that parts genuinely share; follow neighboring context and hook naming. - A default sub-part can sit behind a convenience boolean if it is also exposed for callers needing control. Do not accumulate booleans to configure that default part. Read [EXAMPLES.md](EXAMPLES.md) for worked examples using slots and compound parts.
View on GitHub