Parallel Loading Example
By using multiple <Gueleton> components, you can achieve parallel loading effects on a single page. Skeleton placeholders will display and hide independently based on their respective loading states.
Below is an example with two tweet card components and one user info component that will load data in parallel and display their respective skeleton screens.
Click the Reload Data button to reload all component data.
All configuration options
<template> <div class="flex gap-4 p-4"> <Gueleton :data="data" :data-key="dataKey" :loading="userInfoLoading" :limit="limit" :type="type" :fuzzy="fuzzy" :bone="bone" :container="container" v-slot="{ data }" > <UserCard class="flex-none w-48" avatar="https://i.pravatar.cc/150?img=3" name="Jane Doe" username="janedoe" bio="Lover of technology and nature." :followers="1200" :following="300" /> </Gueleton>
<div class="flex flex-col gap-4"> <Gueleton :data="data" :data-key="dataKey" :loading="loading" :limit="limit" :type="type" :fuzzy="fuzzy" :bone="bone" :container="container" v-slot="{ data }" > <TweetCard v-bind="data?.[0]" /> </Gueleton>
<Gueleton :data="data" :data-key="dataKey" :loading="card2Loading" :limit="limit" :type="type" :fuzzy="fuzzy" :bone="bone" :container="container" v-slot="{ data }" > <TweetCard v-bind="data?.[1]" /> </Gueleton> </div></div></template>
<script setup>import { computed, ref, watch } from 'vue'import TweetCard from './TweetCard.vue';import UserCard from './UserCard.vue';
import { gueletonOptions } from '../../../store/gueleton-options';import { useStore } from '@nanostores/vue';
const $gueletonOptions = useStore(gueletonOptions);
const dataKey = computed(() => $gueletonOptions.value.dataKey);const data = computed(() => $gueletonOptions.value.data);const loading = computed(() => $gueletonOptions.value.loading);
const limit = computed(() => $gueletonOptions.value.limit);
const fuzzy = computed(() => $gueletonOptions.value.fuzzy);const type = computed(() => $gueletonOptions.value.type);const bone = computed(() => $gueletonOptions.value.bone);const container = computed(() => $gueletonOptions.value.container);
const userInfoLoading = ref(loading.value);watch(loading, async (newVal) => { if (newVal) { userInfoLoading.value = true; } else { await new Promise(resolve => setTimeout(resolve, Math.random() * 1000 * 2)); userInfoLoading.value = false; }});
const card2Loading = ref(loading.value);watch(loading, async (newVal) => { if (newVal) { card2Loading.value = true; } else { await new Promise(resolve => setTimeout(resolve, Math.random() * 1000 * 2)); card2Loading.value = false; }});</script><template> <aside class="p-4 border rounded-lg shadow-sm bg-white flex flex-col items-center"> <div class="mb-3"> <img class="h-20 w-20 rounded-full object-cover" :src="avatar" alt="avatar" /> </div> <div class="text-center"> <div class="font-semibold text-lg">{{ name }}</div> <div class="text-gray-500 text-sm mb-2">@{{ username }}</div> <div class="text-gray-700 text-sm mb-4">{{ bio }}</div> </div> <div class="flex gap-6 mb-4"> <div class="text-center"> <div class="font-bold text-base">{{ followers }}</div> <div class="text-xs text-gray-500">followers</div> </div> <div class="text-center"> <div class="font-bold text-base">{{ following }}</div> <div class="text-xs text-gray-500">following</div> </div> </div> <button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition">Follow</button> </aside></template>
<script setup lang="ts">defineProps<{ avatar: string name: string username: string bio?: string followers: number following: number}>()</script><template> <!-- Summary Card (thumbnail) - Tailwind CSS --> <div class="p-4 border rounded-lg shadow-sm bg-white not-content"> <!-- Tweet header --> <div class="flex items-start gap-3"> <div class="h-12 w-12"> <img class="size-full rounded-full object-cover" :src="avatar" alt="avatar"> </div> <div class="flex-1"> <div class="flex items-center gap-2"> <span class="font-semibold text-sm">{{ author }}</span> <span class="text-gray-500 text-sm">@user · {{ date }}</span> </div> <p class="mt-2 text-gray-800"> {{ content }} </p> </div> </div>
<!-- Tweet actions --> <div class="mt-3 flex items-center justify-between text-gray-500 text-sm"> <div class="flex gap-6"> <button class="flex items-center gap-2 hover:text-blue-500">💬 <span>{{ comments }}</span></button> <button class="flex items-center gap-2 hover:text-green-500">🔁 <span>{{ retweets }}</span></button> <button class="flex items-center gap-2 hover:text-red-500">❤️ <span>{{ likes }}</span></button> </div> <div class="text-xs">Translate</div> </div> </div>
</template>
<script setup lang="ts">import type { TweetCard } from '../../../lib/mock-utils';
defineProps<TweetCard>();</script>