In the NOVA LAB Command Center, not all interface modules need a visual representation. Some are responsible solely for logic — these are renderless components. Let's explore advanced Vue component patterns.
A renderless component is a component that does not render its own HTML — instead, it exposes logic through a slot. The parent component defines all the visual appearance.
1<script setup>
2import { ref, onMounted, onUnmounted } from 'vue'
3
4// Renderless component — clock logic
5const now = ref(new Date())
6let timer = null
7
8onMounted(() => {
9 timer = setInterval(() => {
10 now.value = new Date()
11 }, 1000)
12})
13
14onUnmounted(() => clearInterval(timer))
15
16defineExpose({ now })
17</script>
18
19<template>
20 <slot :now="now" :formatted="now.toLocaleTimeString('en-US')" />
21</template>Usage:
1<template>
2 <Clock v-slot="{ formatted }">
3 <div class="station-clock">{{ formatted }}</div>
4 </Clock>
5</template>The
Clock component has no HTML of its own — it passes data through a scoped slot, and the parent decides on the appearance.A popular pattern — a component managing toggle state:
1<!-- Toggle.vue -->
2<script setup>
3import { ref } from 'vue'
4
5const isOn = ref(false)
6
7function toggle() {
8 isOn.value = !isOn.value
9}
10
11function setOn() { isOn.value = true }
12function setOff() { isOn.value = false }
13</script>
14
15<template>
16 <slot :isOn="isOn" :toggle="toggle" :setOn="setOn" :setOff="setOff" />
17</template>Usage in different contexts:
1<template>
2 <!-- As a switch -->
3 <Toggle v-slot="{ isOn, toggle }">
4 <button @click="toggle">
5 System: {{ isOn ? 'ACTIVE' : 'OFFLINE' }}
6 </button>
7 </Toggle>
8
9 <!-- As an expandable panel -->
10 <Toggle v-slot="{ isOn, toggle }">
11 <div>
12 <h3 @click="toggle">Diagnostics ▼</h3>
13 <div v-if="isOn">System details...</div>
14 </div>
15 </Toggle>
16</template>In Vue 3, every component with
<script setup> is already optimized. But you can also create simple functional components as plain render functions:1import { h } from 'vue'
2
3// Functional component — no state, only props
4function StationBadge(props) {
5 return h('span', {
6 class: 'badge',
7 style: {
8 color: props.color || '#00ff88',
9 border: '1px solid ' + (props.color || '#00ff88'),
10 padding: '4px 12px',
11 borderRadius: '12px',
12 fontSize: '12px'
13 }
14 }, props.label)
15}
16
17StationBadge.props = ['label', 'color']Usage in a template:
1<template>
2 <StationBadge label="ONLINE" color="#2ecc71" />
3 <StationBadge label="ALERT" color="#e74c3c" />
4</template>The
h() function (hyperscript) creates a VNode — a virtual DOM element:1import { h } from 'vue'
2
3// h(tag, props, children)
4h('div', { class: 'panel' }, [
5 h('h2', null, 'Title'),
6 h('p', null, 'Panel content')
7])A component with a render function instead of a template:
1import { h, ref, defineComponent } from 'vue'
2
3const Counter = defineComponent({
4 setup() {
5 const count = ref(0)
6
7 return () => h('div', { class: 'counter' }, [
8 h('p', null, 'Counter: ' + count.value),
9 h('button', {
10 onClick: () => count.value++
11 }, '+1')
12 ])
13 }
14})An HOC is a function that takes a component and returns a new component with added functionality:
1import { h, ref, onMounted } from 'vue'
2
3function withLoading(WrappedComponent) {
4 return defineComponent({
5 setup(props, { attrs }) {
6 const loading = ref(true)
7
8 onMounted(() => {
9 setTimeout(() => {
10 loading.value = false
11 }, 1000)
12 })
13
14 return () => {
15 if (loading.value) {
16 return h('div', { class: 'loading' }, 'Loading module...')
17 }
18 return h(WrappedComponent, { ...attrs })
19 }
20 }
21 })
22}Usage:
1const MissionPanelWithLoading = withLoading(MissionPanel)| Pattern | When to Use | |---------|-------------| | Renderless component | Reusable logic with flexible UI | | Functional component | Simple, stateless presentational elements | | Render function (h()) | Dynamic DOM structure generation | | HOC | Adding behavior to existing components |
Renderless components and scoped slots are Vue's idiomatic way of separating logic from presentation — especially useful in systems as complex as the NOVA LAB Command Center.