LiveVue 1.0
Examples Slots

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

1
Default Slot
Main content between tags
2
Named Slots
Header, footer, icon slots
3
Fallback Content
Default content when slot empty
Slots.vue
<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)
Next up: Simple Form with useLiveForm()
View example →