Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Guidance for building UIs with Nuxt UI, the official Tailwind-based component library for Nuxt.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/recipes/overlays.md
1# Overlays23Patterns for modals, slideovers, drawers, and command palettes.45## Confirmation dialog67```vue8<script setup lang="ts">9const isOpen = ref(false)1011function confirmDelete() {12// perform delete13isOpen.value = false14}15</script>1617<template>18<UButton label="Delete" color="error" variant="soft" @click="isOpen = true" />1920<UModal v-model:open="isOpen" title="Delete item" description="This action cannot be undone. Are you sure?" :ui="{ footer: 'justify-end' }">21<template #footer="{ close }">22<UButton label="Cancel" color="neutral" variant="outline" @click="close" />23<UButton label="Delete" color="error" @click="confirmDelete" />24</template>25</UModal>26</template>27```2829## Programmatic confirmation (useOverlay)3031Reusable pattern — no template state needed at the call site.3233```vue [components/ConfirmModal.vue]34<script setup lang="ts">35defineProps<{36title: string37description?: string38}>()3940const emit = defineEmits<{41close: [confirmed: boolean]42}>()43</script>4445<template>46<UModal :close="{ onClick: () => emit('close', false) }" :title="title" :description="description">47<template #footer>48<UButton label="Cancel" color="neutral" variant="outline" @click="emit('close', false)" />49<UButton label="Confirm" color="error" @click="emit('close', true)" />50</template>51</UModal>52</template>53```5455```ts56// Usage anywhere57const overlay = useOverlay()58const confirm = overlay.create(ConfirmModal)5960async function deleteItem(item) {61const instance = confirm.open({62title: 'Delete item',63description: `Are you sure you want to delete "${item.name}"?`64})6566if (await instance.result) {67// user confirmed68}69}70```7172## Form in a slideover7374```vue75<script setup lang="ts">76import * as z from 'zod'7778const isOpen = ref(false)7980const schema = z.object({81name: z.string().min(1),82email: z.email()83})8485type Schema = z.output<typeof schema>86const state = reactive<Partial<Schema>>({})8788function onSave() {89// save user90isOpen.value = false91}92</script>9394<template>95<UButton label="Add user" @click="isOpen = true" />9697<USlideover v-model:open="isOpen" title="Add user" description="Fill in the details below.">98<template #body>99<UForm id="user-form" :schema="schema" :state="state" class="space-y-4" @submit="onSave">100<UFormField name="name" label="Name">101<UInput v-model="state.name" />102</UFormField>103<UFormField name="email" label="Email">104<UInput v-model="state.email" type="email" />105</UFormField>106</UForm>107</template>108109<template #footer="{ close }">110<UButton label="Cancel" color="neutral" variant="outline" @click="close" />111<UButton type="submit" form="user-form" label="Save" />112</template>113</USlideover>114</template>115```116117## Command palette118119```vue120<script setup lang="ts">121const isOpen = ref(false)122123defineShortcuts({124meta_k: () => { isOpen.value = true }125})126127const groups = [{128id: 'actions',129label: 'Actions',130items: [131{ label: 'New file', icon: 'i-lucide-file-plus', kbds: ['meta', 'n'], onSelect: () => newFile() },132{ label: 'New folder', icon: 'i-lucide-folder-plus', onSelect: () => newFolder() }133]134}, {135id: 'navigation',136label: 'Navigation',137items: [138{ label: 'Dashboard', icon: 'i-lucide-house', to: '/dashboard' },139{ label: 'Settings', icon: 'i-lucide-settings', to: '/settings' }140]141}]142</script>143144<template>145<UButton label="Search..." icon="i-lucide-search" color="neutral" variant="outline" @click="isOpen = true" />146147<UCommandPalette v-model:open="isOpen" :groups="groups" placeholder="Type a command or search..." />148</template>149```150151## Drawer (bottom sheet)152153```vue154<script setup lang="ts">155const isOpen = ref(false)156</script>157158<template>159<UButton label="Options" @click="isOpen = true" />160161<UDrawer v-model:open="isOpen" title="Options">162<template #body>163<div class="space-y-2 p-4">164<UButton label="Share" icon="i-lucide-share" block variant="ghost" />165<UButton label="Export" icon="i-lucide-download" block variant="ghost" />166<USeparator />167<UButton label="Delete" icon="i-lucide-trash" block variant="ghost" color="error" />168</div>169</template>170</UDrawer>171</template>172```173174