Skip to main content

Slots

Slots are a way of accepting template blocks from a calling context and displaying them inside another template.

There are three types of slots

  • implicit
  • named
  • dynamic

Implicit Slots

These are by far the most commonly used slots. This is the slot that is used whenever an element has children such as:

template Example render {

SomeSlottedElement() {
Text("This is inside the implicit slot");
}

}

When overriding an implicit slot, you don't have to do anything special, just declare a block and use it. Some elements do not expose an implicit slot, the most common of which is typography elements.

To declare an implicit slot you need to use a declaration member as shown below. Addtionally you must actually render the slot somewhere inside the render block of your template or the compiler will throw an error. This is done to make an element's interface very clear.

template ThingWithImplicitSlot {

slot implicit; // declare that this element has an implicit slot

render {
Text("Before Slot");
render slot->implicit; // render the slot
Text("After Slot");
}

}

Default slot bodies

If a slot is not overridden, you can optionally provide a default block to render instead.

template ThingWithImplicitSlot {

slot implicit; // declare that this element has an implicit slot

render {
Text("Before Slot");

render slot->implicit {
Text("Rendered if the slot is not overridden");
}

Text("After Slot");
}

}

Trivial Containers

A trivial container is a template that does not define a render block. In these cases an implicit slot is generated automatically, as it is assumed that is the intention of the element. If you want to opt-out of the implicit slot generation, you can define a empty render block.


template Trivial;

template DoesNotAcceptChidren render {}

template UsingTrivial render {

Trivial() {
Text("Inside the implicit slot");
}

DoesNotAcceptChildren(); // fine

DoesNotAcceptChildren() {
// error, you cannot use the implicit slot because it is not defined
Text("Compile error!");
}

}

Named Slots

A named slot is a named container that users of your template can optionally override. Unlike an implicit slot, a named slot must be explicitly overridden. It can also accept parameters. Named slots can accept a default block.

A named slot is declared like this:

template ThingWithNamedSlots {

slot title(string s); // declare a named slot 'title' that accepts a string

slot content(int i, float f); // declare a named slot 'content' that accepts an int and a float

render {
Text("Before Slot");

// when rendering the slot, the parameters must be passed in
render slot->title("Some Title");

render slot->content(10, 100f) {
Text("Default slot body");
}

Text("After Slot");
}

}

// when overriding a slot, you can give the parameters whatever names you want, it is the order
// that matters. When overriding slots, the implicit slot must be last.
template NamedSlotExample render {

ThingWithNamedSlots() {

slot->title(str) {
Text($"The title is {str}");
}

Text("Part of implicit slot");
}

}

Dynamic Slots

A dynamic slot is similar to a named slot in that it can accept arguments. There are two main differences:

  • A dynamic slot can only be declared once
  • A dynamic slot can have a name provided by an expression not known at compile time

Dynamic slots don't have a strict naming requirement, any string will do and there is not guarantee that the slot will actually render, it is up to the declaring template to manage which dynamic slots get rendered.

template ThingWithDynamicSlot {

slot dynamic(string s); // declare a dynamic slot that accepts a string

render {
Text("Before Slot");

// when rendering the slot, the parameters must be passed in
// the []
render slot->["one"]("Some string");

render slot->[SomeExpressionReturningAString()]("Some string");

render slot->["three"]("Some string") {
Text("Default slot body");
}

Text("After Slot");
}

}

template SlotExample render {

ThingWithDynamicSlot() {

slot->["one"](value) {
Text("Slot 1");
}

slot->["two"](value) {
Text("Slot 2");
}

slot->["three"](value) {
Text("Slot 3");
}

}
}

Multiple rendering

A slot can be rendered as many times as you like

template ThingWithSlot {

slot implicit;

render {
Text("Before Slot");

render slot->implicit;
render slot->implicit;
render slot->implicit;
render slot->implicit;
render slot->implicit;

Text("After Slot");
}

}