LiveVue
1.0
Slots
Pass HEEx content into Vue components using slots. Combine the power of server-rendered templates with Vue's component composition.
What this example shows
<script setup lang="ts">
import { useSlots, computed } from 'vue'
const props = defineProps<{
title?: string
variant?: 'default' | 'primary' | 'success'
}>()
const slots = useSlots()
const hasHeader = computed(() => !!slots.header)
const hasFooter = computed(() => !!slots.footer)
const hasIcon = computed(() => !!slots.icon)
const variantClasses = computed(() => {
switch (props.variant) {
case 'primary':
return 'border-secondary/30 bg-secondary/5'
case 'success':
return 'border-primary/30 bg-primary/5'
default:
return 'border-base-300'
}
})
</script>
<template>
<div :class="['card overflow-hidden', variantClasses]">
<!-- Header slot -->
<div
v-if="hasHeader || props.title"
class="px-6 py-4 bg-base-200 border-b border-base-300"
>
<div class="flex items-center gap-3">
<div v-if="hasIcon" class="text-neutral">
<slot name="icon" />
</div>
<div class="flex-1">
<slot name="header">
<h3 v-if="props.title" class="font-medium">{{ props.title }}</h3>
</slot>
</div>
</div>
</div>
<!-- Default slot (main content) -->
<div class="p-6">
<slot>
<p class="text-neutral italic">No content provided</p>
</slot>
</div>
<!-- Footer slot -->
<div
v-if="hasFooter"
class="px-6 py-4 bg-base-200 border-t border-base-300"
>
<slot name="footer" />
</div>
</div>
</template>
How it works
1 Vue components define slot insertion points
In the Vue component, use
<slot />
for the default slot and
<slot name="header" />
for named slots. These act as placeholders for content passed from HEEx.
<slot /> <!-- default slot -->
<slot name="header" /> <!-- named slot -->
2 HEEx uses :slot_name syntax to pass content
In LiveView templates, content placed directly between the
<.vue>
tags becomes the default slot. Named slots use the
:slot_name
syntax.
<.vue v-component="Card" v-socket={@socket}>
<:header>Title</:header>
Default slot content
</.vue>
3 Slots can have fallback content
When a slot isn't provided, Vue renders the fallback content inside the
<slot>
tags. This is useful for optional sections or default states.
<slot name="footer">
<p>Default footer content</p>
</slot>
4 Check slot presence in Vue
Use useSlots()
to conditionally render sections based on whether a slot was provided. This enables
flexible layouts that adapt to the content.
const slots = useSlots()
const hasFooter = computed(() => !!slots.footer)