Slots
Slots are named outlets you can define within the component opening and closing tag using the @slot
tag. The component can access slots as functions via the $slots
object.
Let's create a card component and use slots to render different card sections.
@let(attributes = $props
.merge({
class: ['card']
})
.toAttrs()
)
<div {{ attributes }}>
<div class="card_header">
{{{ await $slots.header() }}}
</div>
<div class="card_contents">
{{{ await $slots.content() }}}
</div>
</div>
Now, let's use the card
component and define its contents using slots.
@card({ class: ['card-lg', 'card-shadow'] })
@slot('header')
<strong> Quick start </strong>
@end
@slot('content')
<p> Start building your next project in minutes </p>
@end
@end
Main and named slots
In the previous example, we used named slots to define contents for multiple outlets. However, you can use the main
slot if a component needs just one slot.
The main slot refers to all the contents inside the component's opening and closing tag. In the following example, we accept the card title as a prop and its content as a main
slot.
<div {{ attributes }}>
<div class="card_header">
{{ title }}
</div>
<div class="card_contents">
{{{ await $slots.main() }}}
</div>
</div>
@card({ title: 'Quick start' })
<p> Start building your next project in minutes </p>
@end
Slots scopes
Slots defined using the @slot
tag can access the state of the current template. They do not have access to the component state.
In the following example, we define the cardSize
and the sizes
variables. These variables are available only to the component, not the parent template slots.
@let(cardSize = 'medium')
@let(sizes = {
medium: '350px',
small: '200px',
large: '450px'
})
<div class="{{ sizes[cardSize] }}">
<div class="card_header">
{{{ await $slots.header() }}}
</div>
<div class="card_contents">
{{{ await $slots.content() }}}
</div>
</div>
@card()
@slot('header')
<strong> Quick start </strong>
@end
@slot('content')
{{-- The value of cardSize will be undefined --}}
<p> I am a {{ cardSize }} card </p>
@end
@end
However, a component can pass data to the slot when rendering it. Let's look at the following example:
@let(cardSize = 'medium')
@let(sizes = {
medium: '350px',
small: '200px',
large: '450px'
})
<div class="{{ sizes[cardSize] }}">
<div class="card_header">
{{{ await $slots.header({ sizes, cardSize }) }}}
</div>
<div class="card_contents">
{{{ await $slots.content({ sizes, cardSize }) }}}
</div>
</div>
Now, you can access the shared state inside the @slot
component as follows.
@card()
@slot('header')
<strong> Quick start </strong>
@end
@slot('content', componentState)
<p> I am a {{ componentState.cardSize }} card </p>
@end
@end