Composition
Understand Moraine component architecture, single vs composite components, public parts, style slots, and DOM ownership.
Moraine components balance ergonomic simplicity with deep compositional control. Every component exposes its structure through JSX parts and its styling surface through slots.
Component Kinds#
Single Components#
A Single component renders through a single JSX element. It manages its internal DOM structure and styling slots internally.
Examples include Button, Badge, Input, and Checkbox:
Composite Components#
A Composite component exposes modular, attached JSX parts that you arrange in your layout. This gives you direct control over markup order, nested text, and layout wrappers.
Examples include Card, Dialog, Accordion, and SidebarFrame:
Parts vs Slots#
Understanding the distinction between parts and slots is key to working effectively with Moraine:
| Concept | What it is | How to use |
|---|---|---|
| Part | An attached JSX component | Arranged directly in template (<Dialog.Content>) |
| Slot | A named styling target within the component | Targeted via classes={{ slotName: '...' }} |
- A public part is a real JSX component that can accept child elements, props, and DOM attributes.
- A slot is an internal styling hook (such as
contentCloseoritemLabel). Slots appear in theclassesandstylestypes and matchdata-slotattributes in the rendered DOM. - Not every slot corresponds to an attached public part. For detailed styling rules, see Customization.
DOM Ownership#
DOM Roots#
Components like Card, Button, and Input render their own top-level container element in the DOM. DOM attributes (id, aria-*, data-*, class) placed on the component pass directly to that root element.
State-only Roots#
Components like Dialog, Popover, Sheet, and BaseSelect manage reactive state, context, and focus trapping without rendering a wrapper element in the DOM:
In state-only roots:
- Direct DOM attributes belong on rendered parts (such as
Dialog.ContentorDialog.Trigger). - Setting
classesorstyleson the root sets default slot styles that cascade to all descendant parts.
Polymorphism (as Prop)#
Components and rendered parts that expose as support a different HTML tag or SolidJS component. State-only roots and native form controls such as Input do not expose this prop. Check the component’s API before changing its element:
For complete details on type preservation and event forwarding, see the dedicated Polymorphism guide.
Reading Component Anatomy#
Component documentation includes an Anatomy tree showing:
- The hierarchy of attached public parts
- The corresponding slot names
- Annotations showing whether a root renders a DOM node (
slot=root) or manages state (no DOM)