N
Nuxt2mo ago
Mads

Add content to UModal with useOverlay()

So I am using UModal with useOverlay() from Nuxt UI. I'd like to be able to pass in some content to the modal, but how does this work? modal.patch({ title: 'Vi har hentet data fra XXX', body: <ul class="space-y-2 list-disc list-inside text-sm">${updatedValues.map(value => <li>${value}</li>).join('')}</ul>, footer: { actions: [ { label: 'Luk', onClick: () => modal.close(), }, ], }, })
8 Replies
kapa.ai
kapa.ai2mo ago
Hi @Mads. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To add content to a UModal when using useOverlay() in Nuxt UI, you should pass props that your modal component is set up to receive and render. The modal content is not injected via a body or footer prop containing raw HTML or objects, but rather through props and slots in your modal component. How it works: 1. Define your modal component to accept props (e.g., title, items, etc.) and use those props in the template. Use slots for more complex or dynamic content. 2. When using useOverlay(), you can update the props of the modal using modal.patch({ ... }). However, you cannot directly inject raw HTML or slot content via patch. Instead, pass data (like an array of items) as props, and let the modal component render them. Example: Suppose you want to display a list in the modal body. Define your modal like this:
<!-- ModalExample.vue -->
<script setup lang="ts">
defineProps<{ title: string; items: string[] }>()
const emit = defineEmits<{ close: [] }>()
</script>

<template>
<UModal :title="title">
<template #body>
<ul class="space-y-2 list-disc list-inside text-sm">
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</template>
<template #footer>
<UButton label="Luk" @click="emit('close')" />
</template>
</UModal>
</template>
<!-- ModalExample.vue -->
<script setup lang="ts">
defineProps<{ title: string; items: string[] }>()
const emit = defineEmits<{ close: [] }>()
</script>

<template>
<UModal :title="title">
<template #body>
<ul class="space-y-2 list-disc list-inside text-sm">
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</template>
<template #footer>
<UButton label="Luk" @click="emit('close')" />
</template>
</UModal>
</template>
Then, in your main component:
import { LazyModalExample } from '#components'
const overlay = useOverlay()
const modal = overlay.create(LazyModalExample, {
props: {
title: 'Vi har hentet data fra XXX',
items: updatedValues
}
})

// To update the content later:
modal.patch({
title: 'Ny titel',
items: newUpdatedValues
})
import { LazyModalExample } from '#components'
const overlay = useOverlay()
const modal = overlay.create(LazyModalExample, {
props: {
title: 'Vi har hentet data fra XXX',
items: updatedValues
}
})

// To update the content later:
modal.patch({
title: 'Ny titel',
items: newUpdatedValues
})
Key points: - Pass data as props, not as raw HTML or slot objects. - The modal component should render the content using those props. - You cannot pass slot content or render functions via patch—only props. For more details, see the programmatic usage example for modals and the useOverlay composable documentation[^1^][^2^]. [^1^]: Modal programmatic usage [^2^]: useOverlay composable If you need to render more complex content, consider passing data as props and using slots in your modal component to render it accordingly. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@335112909350895632> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Mads
MadsOP2mo ago
But i'd like it styled, i don't even see items as a prop in the modal. I should be able to use the body prop, but not really sure how I pass in the HTML through script setup. Can I H render it first? I meant body slot @kapa.ai
kapa.ai
kapa.ai2mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- To add content to the body slot of a UModal when using useOverlay(), you need to design your modal component so that it uses the #body slot for displaying content. You cannot pass slot content (like a template or VNodes) through modal.patch() or as a prop; instead, you should pass data as props and let the modal component render it in the body slot. Example: Suppose you want to display a list in the modal's body. Your modal component might look like this:
<!-- ModalExample.vue -->
<script setup lang="ts">
defineProps<{ title: string; items: string[] }>()
const emit = defineEmits<{ close: [] }>()
</script>

<template>
<UModal :title="title">
<template #body>
<ul class="space-y-2 list-disc list-inside text-sm">
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</template>
<template #footer>
<UButton label="Luk" @click="emit('close')" />
</template>
</UModal>
</template>
<!-- ModalExample.vue -->
<script setup lang="ts">
defineProps<{ title: string; items: string[] }>()
const emit = defineEmits<{ close: [] }>()
</script>

<template>
<UModal :title="title">
<template #body>
<ul class="space-y-2 list-disc list-inside text-sm">
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</template>
<template #footer>
<UButton label="Luk" @click="emit('close')" />
</template>
</UModal>
</template>
Then, when using useOverlay():
import { LazyModalExample } from '#components'
const overlay = useOverlay()
const modal = overlay.create(LazyModalExample, {
props: {
title: 'Vi har hentet data fra XXX',
items: updatedValues
}
})

// To update the content later:
modal.patch({
items: newUpdatedValues
})
import { LazyModalExample } from '#components'
const overlay = useOverlay()
const modal = overlay.create(LazyModalExample, {
props: {
title: 'Vi har hentet data fra XXX',
items: updatedValues
}
})

// To update the content later:
modal.patch({
items: newUpdatedValues
})
Summary:
You cannot directly inject slot content (like the body slot) via modal.patch() or as a prop. Instead, pass the data your modal needs as props, and render it inside the #body slot in your modal component. This is the recommended and supported approach according to the Nuxt UI documentation on programmatic modal usage and slot usage Modal programmatic usage Modal slots. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@335112909350895632> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Mads
MadsOP2mo ago
But i'd like it styled, i don't even see items as a prop in the modal. I should be able to use the body prop, but not really sure how I pass in the HTML through script setup. Can I H render it first? I meant body slot @kapa.ai
kapa.ai
kapa.ai2mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- You are correct that the UModal component itself does not have an items prop by default. The content inside the modal—including the body slot—should be defined in your modal component’s template, not passed as a prop or as raw HTML via modal.patch(). Key points from the documentation: - The body slot is used to customize the modal’s body content. You define what appears in the body slot in your modal component’s template, not by passing HTML or VNodes through the overlay API Modal slots. - When using useOverlay(), you can only pass data as props. You cannot pass raw HTML or slot content through modal.patch() or modal.open()—the overlay system does not support rendering arbitrary HTML or VNodes passed as props useOverlay composable. What does this mean for your use case? - If you want styled content in the body slot, you should pass the data (such as an array of strings) as a prop, and then render it with the desired markup and styling inside the body slot in your modal component. - You cannot use a body prop to inject HTML or a render function into the slot from the parent or via modal.patch(). Example:
<!-- ModalExample.vue -->
<script setup lang="ts">
defineProps<{ title: string; items: string[] }>()
const emit = defineEmits<{ close: [] }>()
</script>

<template>
<UModal :title="title">
<template #body>
<ul class="space-y-2 list-disc list-inside text-sm">
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</template>
<template #footer>
<UButton label="Luk" @click="emit('close')" />
</template>
</UModal>
</template>
<!-- ModalExample.vue -->
<script setup lang="ts">
defineProps<{ title: string; items: string[] }>()
const emit = defineEmits<{ close: [] }>()
</script>

<template>
<UModal :title="title">
<template #body>
<ul class="space-y-2 list-disc list-inside text-sm">
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</template>
<template #footer>
<UButton label="Luk" @click="emit('close')" />
</template>
</UModal>
</template>
Then, from your parent component:
const modal = overlay.create(LazyModalExample, {
props: {
title: 'Vi har hentet data fra XXX',
items: updatedValues
}
})
const modal = overlay.create(LazyModalExample, {
props: {
title: 'Vi har hentet data fra XXX',
items: updatedValues
}
})
Summary:
You cannot pass HTML or a render function to the body slot via modal.patch() or as a prop. The content of the body slot must be defined in the modal component’s template, and you can pass data as props to be rendered and styled as you wish inside that slot. This is the only approach documented and supported by Nuxt UI Modal slots useOverlay composable. If you need to render arbitrary HTML, you would need to use a prop (e.g., html) and then use v-html in your slot, but this is not shown or recommended in the official documentation, and you should be cautious with XSS if you go this route. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@335112909350895632> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?