# Strapi + Vue SPA, variant flashes after the default renders

Asked by nikos_p on 2026-06-04. Tags: strapi, vue, spa.

hey, we have a classic SPA, Vue 3 + Strapi backend, no SSR. I'm fetching the personalized hero like this:

```vue
<script setup>
import {ref, onMounted} from 'vue';
import croct from '@croct/plug';

const hero = ref(null);

onMounted(async () => {
    const {content} = await croct.fetch('home-hero');
    hero.value = content;
});
</script>
```

Works, but users see the Strapi default hero for a beat and then the variant swaps in. Looks cheap on slower connections. Is there a way to aviod the flash without migrating the whole thing to Nuxt? that's not on the table this quarter

## 2 answers

### Answer from andresv (2026-06-05)

The flash comes from when you fetch, not from the SPA itself. `onMounted` runs after the component has already rendered, so the default is on screen before the variant arrives. SPA support is flicker-free when the content is resolved before render rather than after mount.

Move the fetch into setup and await it, then gate the section behind Suspense:

```vue
<script setup>
import croct from '@croct/plug';

const {content: hero} = await croct.fetch('home-hero');
</script>
```

With a top-level await in setup the component becomes async, so wrap it in `<Suspense>` in the parent. The section then renders once, with the right content, no swap.

Also give the fetch a fallback so the Strapi default serves if the request fails for any reason:

```js
const {content: hero} = await croct.fetch('home-hero')
    .catch(() => ({content: strapiDefaultHero}));
```

#### Reply from nikos_p (2026-06-05)

moved it into setup with Suspense and the swap is gone. didn't realize the async setup pattern was all it took, thanks!

### Answer from katya_m (2026-06-06)

Small alternative if you would rather not introduce Suspense: keep the fetch in setup without await and gate just the hero markup with `v-if="hero"`, rendering nothing (or a fixed-height skeleton) until content resolves. Same principle, resolve before you show anything, so there is never a default-to-variant swap.

Also, since you are on Vue anyway, the dedicated Vue SDK gives you a plugin and composables instead of the vanilla plug, which makes this pattern a bit less manual. But either approach kills the flash.
