HypenHypen
Guide

Child Slots

Build reusable components that accept and place children with Children() and named slots

Child Slots

Slots let a reusable component accept children from its call site and render them in specific places inside its own template. A component marks each insertion point with the Children() placeholder. You can have a single default slot or several named slots.

Slots are how you build wrappers like cards, dialogs, and layouts that stay declarative — the component owns the chrome, the caller owns the content.

The default slot

Put Children() anywhere in a component's template to mark where the caller's children should render.

// Card.hypen — a reusable component
Column {
    Column {
        Text("Card")
            .fontWeight("bold")
    }
    .padding(16)
    .backgroundColor("#f0f0f0")

    Column {
        Children()
    }
    .padding(16)
}

Everything you nest inside Card at the call site is inserted where Children() sits:

Card {
    Text("Card content goes here")
    Button { Text("Toggle") }
        .onClick(@actions.toggle)
}

If a component is used with no children, the Children() placeholder simply renders nothing — surrounding template content stays put.

Named slots

For components with more than one insertion point, give each Children() placeholder a name with the .slot("name") applicator:

// CardWithSlots.hypen
Column {
    Column {
        Children().slot("header")
    }
    .padding(16)
    .backgroundColor("#2196F3")
    .color("white")

    Column {
        Children().slot("body")
    }
    .padding(24)

    Column {
        Children().slot("footer")
    }
    .padding(16)
    .backgroundColor("#f5f5f5")
}

At the call site, tag each child with the matching .slot("name") to route it to that placeholder:

CardWithSlots {
    Column {
        Text("@{state.title}")
    }.slot("header")

    Column {
        Text("This is the main content area")
        Text("You can add multiple elements here")
    }.slot("body")

    Row {
        Button { Text("Highlight") }
            .onClick(@actions.toggleHighlight)
    }.slot("footer")
}

Each named placeholder collects only the children whose .slot() name matches it, preserving their call-site order.

Combining default and named slots

A component can mix a default slot with named slots. Any child that has no .slot() applicator falls into the default slot; children with a .slot() name go to the matching named slot.

// Panel.hypen
Column {
    Column {
        Children().slot("header")
    }
    .padding(16)

    Column {
        Children()   // default slot — everything without a .slot()
    }
    .padding(16)
}
Panel {
    Text("Panel Header").slot("header")

    // These have no .slot(), so they land in the default slot
    Text("Default content 1")
    Text("Default content 2")
}

Behavior details

  • Multiple children per slot — a slot collects every matching child, in order. A Children().slot("actions") placeholder happily holds several buttons.
  • Nesting — components with slots compose. A slotted component can be passed as a child to another slotted component, and each expands independently.
  • Deep placementChildren() can sit anywhere in the template tree, not just at the top level. It's replaced wherever it appears.
  • Control-flow childrenForEach, When, and If blocks passed as children always go to the default slot (they don't carry a .slot() name).
  • Unmatched slots — a child tagged .slot("x") when the component has no Children().slot("x") placeholder is dropped, and an empty slot renders nothing. Match names carefully.

Registering slot components

A slot component is an ordinary Hypen component — a .hypen template with no required state. Register it the same way as any other component: place the template in your components directory (folder, sibling, or index pattern) and it's picked up by discovery as a stateless component.

src/components/
  Card/
    component.hypen    # template with Children() — no .ts needed

See TypeScript Server → Component Patterns for the full set of file layouts and how discovery loads templates.

Next Steps

  • Components — Reference of all built-in components
  • Control Flow — ForEach, When, If in depth
  • Layout — Arranging content with Column, Row, and friends