We use cookies to enhance your experience on the site
CodeWorlds

Advanced Slot Patterns

Now that you know all the NOVA LAB module storage tools, let's see how to combine them into advanced patterns - like a complete station logistics system.

Renderless Components

A renderless component is a component that has no template of its own - it only provides logic through a scoped slot. The parent has full control over rendering.

1<!-- MissionTimer.vue (renderless) -->
2<script setup>
3import { ref, onMounted, onUnmounted } from 'vue'
4
5const count = ref(0)
6const isRunning = ref(false)
7let interval = null
8
9const start = () => {
10  if (!isRunning.value) {
11    isRunning.value = true
12    interval = setInterval(() => count.value++, 1000)
13  }
14}
15
16const stop = () => {
17  isRunning.value = false
18  clearInterval(interval)
19}
20
21const reset = () => {
22  count.value = 0
23  stop()
24}
25
26onUnmounted(() => clearInterval(interval))
27</script>
28
29<template>
30  <slot
31    :count="count"
32    :isRunning="isRunning"
33    :start="start"
34    :stop="stop"
35    :reset="reset"
36  />
37</template>
38
39<!-- Usage with any UI -->
40<MissionTimer v-slot="{ count, isRunning, start, stop, reset }">
41  <div class="timer">
42    <h2>{{ count }}s</h2>
43    <button v-if="!isRunning" @click="start">Start</button>
44    <button v-else @click="stop">Pause</button>
45    <button @click="reset">Reset</button>
46  </div>
47</MissionTimer>

Dynamic Slot Names

Slot names can be dynamic:

1<script setup>
2import { ref } from 'vue'
3const activeSection = ref('header')
4</script>
5
6<template>
7  <StationPanel>
8    <template v-slot:[activeSection]>
9      <p>Dynamic content for {{ activeSection }}</p>
10    </template>
11  </StationPanel>
12</template>

useSlots()

Checking which slots have been provided:

1<script setup>
2import { useSlots } from 'vue'
3
4const slots = useSlots()
5
6// Check if a slot exists
7const hasHeader = !!slots.header
8const hasFooter = !!slots.footer
9</script>
10
11<template>
12  <div class="panel">
13    <header v-if="slots.header">
14      <slot name="header" />
15    </header>
16    <main>
17      <slot />
18    </main>
19    <footer v-if="slots.footer">
20      <slot name="footer" />
21    </footer>
22  </div>
23</template>

Slot Forwarding

An intermediate component can forward slots further down:

1<!-- Wrapper.vue -->
2<template>
3  <InnerComponent>
4    <template v-for="(_, name) in $slots" #[name]="slotProps">
5      <slot :name="name" v-bind="slotProps || {}" />
6    </template>
7  </InnerComponent>
8</template>

When to Use Which Pattern?

| Pattern | When to Use | |---------|------------| | Props | Simple data (string, number, boolean) | | Default slot | Injecting arbitrary HTML | | Named slots | Multiple sections to fill | | Scoped slots | Rendering dependent on child's data | | Renderless | Logic only, full UI control | | Dynamic components | Switching between components | | Teleport | Rendering outside the DOM hierarchy | | Async + Suspense | Lazy loading heavy components |

Go to CodeWorlds