Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Apply VueUse composables in Vue 3/Nuxt projects to replace custom implementations with battle-tested utilities.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/createTemplatePromise.md
1---2category: Component3outline: deep4---56# createTemplatePromise78Template as Promise. Useful for constructing custom Dialogs, Modals, Toasts, etc.910## Usage1112```vue13<script setup lang="ts">14import { createTemplatePromise } from '@vueuse/core'1516const TemplatePromise = createTemplatePromise<ReturnType>()1718async function open() {19const result = await TemplatePromise.start()20// button is clicked, result is 'ok'21}22</script>2324<template>25<TemplatePromise v-slot="{ promise, resolve, reject, args }">26<!-- your UI -->27<button @click="resolve('ok')">28OK29</button>30</TemplatePromise>31</template>32```3334## Features3536- **Programmatic** - call your UI as a promise37- **Template** - use Vue template to render, not a new DSL38- **TypeScript** - full type safety via generic type39- **Renderless** - you take full control of the UI40- **Transition** - use support Vue transition4142This function is migrated from [vue-template-promise](https://github.com/antfu/vue-template-promise)4344## Usage4546`createTemplatePromise` returns a **Vue Component** that you can directly use in your template with `<script setup>`4748```ts twoslash include main49import { createTemplatePromise } from '@vueuse/core'5051const TemplatePromise = createTemplatePromise()52const MyPromise = createTemplatePromise<boolean>() // with generic type53```5455In template, use `v-slot` to access the promise and resolve functions.5657```vue58<template>59<TemplatePromise v-slot="{ promise, resolve, reject, args }">60<!-- you can have anything -->61<button @click="resolve('ok')">62OK63</button>64</TemplatePromise>65<MyPromise v-slot="{ promise, resolve, reject, args }">66<!-- another one -->67</MyPromise>68</template>69```7071The slot will not be rendered initially (similar to `v-if="false"`), until you call the `start` method from the component.7273```ts74// @include: main75// ---cut---76const result = await TemplatePromise.start()77```7879Once `resolve` or `reject` is called in the template, the promise will be resolved or rejected, returning the value you passed in. Once resolved, the slot will be removed automatically.8081### Passing Arguments8283You can pass arguments to the `start` with arguments.8485```ts twoslash include passing-arguments86import { createTemplatePromise } from '@vueuse/core'8788const TemplatePromise = createTemplatePromise<boolean, [string, number]>()89```9091```ts92// @include: passing-arguments93// ---cut---94const result = await TemplatePromise.start('hello', 123) // Pr95```9697And in the template slot, you can access the arguments via `args` property.9899```vue100<template>101<TemplatePromise v-slot="{ args, resolve }">102<div>{{ args[0] }}</div>103<!-- hello -->104<div>{{ args[1] }}</div>105<!-- 123 -->106<button @click="resolve(true)">107OK108</button>109</TemplatePromise>110</template>111```112113### Singleton Mode114115Use the `singleton` option to ensure only one instance of the promise can be active at a time. If `start` is called while a promise is already active, it will return the existing promise instead of creating a new one.116117```ts118import { createTemplatePromise } from '@vueuse/core'119120const TemplatePromise = createTemplatePromise<boolean>({121singleton: true,122})123124// These will return the same promise if called in quick succession125const result1 = TemplatePromise.start()126const result2 = TemplatePromise.start() // returns the same promise as result1127```128129### Transition130131You can use transition to animate the slot.132133```vue134<script setup lang="ts">135const TemplatePromise = createTemplatePromise<ReturnType>({136transition: {137name: 'fade',138appear: true,139},140})141</script>142143<template>144<TemplatePromise v-slot="{ resolve }">145<!-- your UI -->146<button @click="resolve('ok')">147OK148</button>149</TemplatePromise>150</template>151152<style scoped>153.fade-enter-active,154.fade-leave-active {155transition: opacity 0.5s;156}157.fade-enter,158.fade-leave-to {159opacity: 0;160}161</style>162```163164Learn more about [Vue Transition](https://vuejs.org/guide/built-ins/transition.html).165166### Slot Props167168The slot provides the following props:169170| Prop | Type | Description |171| ------------- | ---------------------------------------- | --------------------------------------------------------- |172| `promise` | `Promise<Return> \| undefined` | The current promise instance |173| `resolve` | `(v: Return \| Promise<Return>) => void` | Resolve the promise with a value |174| `reject` | `(v: any) => void` | Reject the promise |175| `args` | `Args` | Arguments passed to `start()` |176| `isResolving` | `boolean` | `true` when resolving another promise passed to `resolve` |177| `key` | `number` | Unique key for list rendering |178179```vue180<template>181<TemplatePromise v-slot="{ promise, resolve, reject, args, isResolving }">182<div v-if="isResolving">183Loading...184</div>185<div v-else>186<button @click="resolve('ok')">187OK188</button>189<button @click="reject('cancelled')">190Cancel191</button>192</div>193</TemplatePromise>194</template>195```196197## Motivation198199The common approach to call a dialog or a modal programmatically would be like this:200201```ts202const dialog = useDialog()203const result = await dialog.open({204title: 'Hello',205content: 'World',206})207```208209This would work by sending these information to the top-level component and let it render the dialog. However, it limits the flexibility you could express in the UI. For example, you could want the title to be red, or have extra buttons, etc. You would end up with a lot of options like:210211```ts212const result = await dialog.open({213title: 'Hello',214titleClass: 'text-red',215content: 'World',216contentClass: 'text-blue text-sm',217buttons: [218{ text: 'OK', class: 'bg-red', onClick: () => {} },219{ text: 'Cancel', class: 'bg-blue', onClick: () => {} },220],221// ...222})223```224225Even this is not flexible enough. If you want more, you might end up with manual render function.226227```ts228const result = await dialog.open({229title: 'Hello',230contentSlot: () => h(MyComponent, { content }),231})232```233234This is like reinventing a new DSL in the script to express the UI template.235236So this function allows **expressing the UI in templates instead of scripts**, where it is supposed to be, while still being able to be manipulated programmatically.237238## Type Declarations239240```ts241export interface TemplatePromiseProps<Return, Args extends any[] = []> {242/**243* The promise instance.244*/245promise: Promise<Return> | undefined246/**247* Resolve the promise.248*/249resolve: (v: Return | Promise<Return>) => void250/**251* Reject the promise.252*/253reject: (v: any) => void254/**255* Arguments passed to TemplatePromise.start()256*/257args: Args258/**259* Indicates if the promise is resolving.260* When passing another promise to `resolve`, this will be set to `true` until the promise is resolved.261*/262isResolving: boolean263/**264* Options passed to createTemplatePromise()265*/266options: TemplatePromiseOptions267/**268* Unique key for list rendering.269*/270key: number271}272export interface TemplatePromiseOptions {273/**274* Determines if the promise can be called only once at a time.275*276* @default false277*/278singleton?: boolean279/**280* Transition props for the promise.281*/282transition?: TransitionGroupProps283}284export type TemplatePromise<285Return,286Args extends any[] = [],287> = DefineComponent<object> & {288new (): {289$slots: {290default: (_: TemplatePromiseProps<Return, Args>) => any291}292}293} & {294start: (...args: Args) => Promise<Return>295}296/**297* Creates a template promise component.298*299* @see https://vueuse.org/createTemplatePromise300*301* @__NO_SIDE_EFFECTS__302*/303export declare function createTemplatePromise<Return, Args extends any[] = []>(304options?: TemplatePromiseOptions,305): TemplatePromise<Return, Args>306```307