Suspense

Suspense can be used to show a fallback element when an async work is needed in the main component

<Suspense>
  <template #default>
    <!-- The component I want to render -->
  </template>
  <template #fallback>
    <!-- Fallback component shown while my component is not ready -->
  </template>
</Suspense>

Wrapping the logic

<template>
  <slot v-if="error" name="error"></slot>
  <Suspense v-else>
    <template #default>
      <slot name="default"></slot>
    </template>
    <template #fallback>
      <slot name="fallback"></slot>
    </template>
  </Suspense>
</template>

<script>
import { ref, onErrorCaptured } from 'vue'

export default {
  name: 'SuspenseWithError',
  setup() {
    const error = ref(null);

    onErrorCaptured((e) => {
      error.value = e

      return true;
    });
    
    return { error };
  }
}
</script>
<template>
  <SuspenseWithError>
    <template #default>
      <MyAsyncComponent />
    </template>
    <template #fallback>
      <span>Loading... Please wait.</span>
    </template>
    <template #error>
      <h1>I failed to load</h1>
    </template>
  </Suspense>
</template>

<script>
import MyAsyncComponent from '@/components/MyAsyncComponent.vue';
import SuspenseWithError from '@/components/SuspenseWithError.vue';

export default {
  name: 'App',
  components: { MyAsyncComponent, SuspenseWithError },
}
</script>

Go async in Vue 3 with Suspense

Slots

You can pass content to a component using a slot

Basic Slot

Outputting a profile component

<profile url="/profile">
  Shane Prendergast
</profile>

Within the actual profile component (profile.vue)

<a v-bind:href="url">
  <slot></slot>
</a>

Outputs

<a href="/profile">
  Shane Prendergast
</a>

Slots can contain any code, including HTML and other components. If no is defined, any content passed into the component would be discarded.

Named Slots

Profile component (profile.vue)

<div>

  <div class="profile__name">
    <slot name="name"></slot>
  </div>

  <slot></slot>

  <div class="profile__contact">
    <slot name="contact"></slot>
  </div>

</div>

Using the profile card component with the slots, notice how you can either use