[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"post-vue3-teleport-suspense-advanced-patterns":3,"parsed-post-3d6e2b0b-d6b4-4c90-8bd3-fb7b6960fcd4":80,"header-categories":239},{"success":4,"data":5},true,{"id":6,"slug":7,"title":8,"excerpt":9,"content":10,"status":11,"visibility":12,"featuredImage":13,"canonicalUrl":14,"readingTime":15,"viewCount":16,"commentEnabled":4,"publishedAt":17,"scheduledAt":14,"createdAt":18,"updatedAt":19,"seoTitle":20,"seoDescription":9,"seoKeywords":14,"authorId":21,"author":22,"coAuthors":27,"tags":28,"categories":39,"comments":48,"_count":49,"relatedPosts":51},"3d6e2b0b-d6b4-4c90-8bd3-fb7b6960fcd4","vue3-teleport-suspense-advanced-patterns","Vue 3 Teleport and Suspense: Advanced Component Patterns","Master Vue 3's built-in components for modals, loading states, and async component coordination with Teleport and Suspense.","## Teleport: Render Anywhere in the DOM\n\nTeleport renders a component's template in a different DOM location while keeping it in the same logical component tree.\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv class=\"relative\">\n    \u003Cbutton @click=\"showModal = true\">Open Modal\u003C\u002Fbutton>\n\n    \u003C!-- Renders at document body, not inside this div -->\n    \u003CTeleport to=\"body\">\n      \u003Cdiv v-if=\"showModal\" class=\"fixed inset-0 z-50 flex items-center justify-center\">\n        \u003Cdiv class=\"fixed inset-0 bg-black\u002F50\" @click=\"showModal = false\" \u002F>\n        \u003Cdiv class=\"relative bg-white rounded-xl p-6 max-w-md w-full\">\n          \u003Ch2 class=\"text-lg font-bold\">Modal Title\u003C\u002Fh2>\n          \u003Cp>This renders at the body level, avoiding z-index issues.\u003C\u002Fp>\n          \u003Cbutton @click=\"showModal = false\">Close\u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002FTeleport>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup lang=\"ts\">\nconst showModal = ref(false)\n\u003C\u002Fscript>\n```\n\n### Why Teleport?\n\n- Avoids `overflow: hidden` clipping on parent containers\n- Fixes z-index stacking context issues\n- Keeps component logic colocated with its trigger\n\n## Suspense: Async Component Coordination\n\nSuspense shows fallback content while async components or setup functions resolve:\n\n```vue\n\u003Ctemplate>\n  \u003CSuspense>\n    \u003Ctemplate #default>\n      \u003CAsyncDashboard \u002F>\n    \u003C\u002Ftemplate>\n    \u003Ctemplate #fallback>\n      \u003CDashboardSkeleton \u002F>\n    \u003C\u002Ftemplate>\n  \u003C\u002FSuspense>\n\u003C\u002Ftemplate>\n```\n\nThe async component:\n\n```vue\n\u003C!-- AsyncDashboard.vue -->\n\u003Cscript setup lang=\"ts\">\n\u002F\u002F This makes the component \"async\" — Suspense will wait for it\nconst { data: stats } = await useFetch('\u002Fapi\u002Fdashboard\u002Fstats')\nconst { data: activity } = await useFetch('\u002Fapi\u002Fdashboard\u002Factivity')\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv class=\"grid grid-cols-3 gap-4\">\n    \u003CStatCard v-for=\"stat in stats\" :key=\"stat.id\" v-bind=\"stat\" \u002F>\n  \u003C\u002Fdiv>\n  \u003CActivityFeed :items=\"activity\" \u002F>\n\u003C\u002Ftemplate>\n```\n\n::callout{icon=\"i-lucide-loader\" color=\"info\"}\nWith Suspense, you can have multiple async components that all resolve before showing anything — no more cascading loading spinners.\n::\n\n## Error Handling with Suspense\n\n```vue\n\u003Cscript setup lang=\"ts\">\nconst error = ref\u003CError | null>(null)\n\nfunction onError(e: Error) {\n  error.value = e\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv v-if=\"error\" class=\"text-red-500\">\n    Something went wrong: {{ error.message }}\n  \u003C\u002Fdiv>\n\n  \u003CSuspense v-else @error=\"onError\">\n    \u003Ctemplate #default>\n      \u003CAsyncContent \u002F>\n    \u003C\u002Ftemplate>\n    \u003Ctemplate #fallback>\n      \u003CLoadingSpinner \u002F>\n    \u003C\u002Ftemplate>\n  \u003C\u002FSuspense>\n\u003C\u002Ftemplate>\n```\n\n## Combining Teleport + Suspense\n\n```vue\n\u003Ctemplate>\n  \u003CTeleport to=\"#notification-area\">\n    \u003CSuspense>\n      \u003Ctemplate #default>\n        \u003CAsyncNotifications \u002F>\n      \u003C\u002Ftemplate>\n      \u003Ctemplate #fallback>\n        \u003CNotificationSkeleton \u002F>\n      \u003C\u002Ftemplate>\n    \u003C\u002FSuspense>\n  \u003C\u002FTeleport>\n\u003C\u002Ftemplate>\n```\n\nThese built-in components solve real layout and async coordination problems. Use them to build smoother user experiences.\n","published","public","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1498050108023-c5249f4df085?w=1200&q=80",null,8,1565,"2026-05-24T06:03:57.898Z","2026-07-24T06:03:57.902Z","2026-07-28T17:14:06.897Z","Vue 3 Teleport and Suspense: Advanced Component Patterns | BitBlog","fddb5d93-7a2c-4d86-a06a-fa32e73a01c6",{"email":23,"bio":24,"id":21,"name":25,"avatarUrl":26},"mbeahessilfieprince@gmail.com","Fullstack Software Developer ","Mbeah Essilfie","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F93322394?v=4",[],[29,34],{"id":30,"name":31,"color":32,"description":33},"typescript","TypeScript","#3178c6","Typed superset of JavaScript",{"id":35,"name":36,"color":37,"description":38},"vue","Vue","#4fc08d","The Progressive JavaScript Framework",[40,44],{"id":41,"name":42,"description":43},"web-development","Web Development","Frontend and backend web development tutorials and guides",{"id":45,"name":46,"description":47},"tutorials","Tutorials","Step-by-step learning guides",[],{"comments":50},0,[52,60,70],{"id":53,"slug":54,"title":55,"excerpt":56,"featuredImage":13,"viewCount":57,"readingTime":15,"publishedAt":58,"author":59},"2997028f-4d22-4eb7-9d86-894a54cb559a","building-type-safe-apis-nuxt3-prisma","Building Type-Safe APIs with Nuxt 3 and Prisma","Learn how to build end-to-end type-safe APIs using Nuxt 3 server routes and Prisma ORM for a seamless developer experience.",1922,"2026-07-23T06:02:46.910Z",{"id":21,"name":25,"avatarUrl":26},{"id":61,"slug":62,"title":63,"excerpt":64,"featuredImage":65,"viewCount":66,"readingTime":67,"publishedAt":68,"author":69},"da9e4553-8b0d-411e-b4ec-f9684017e163","mastering-tailwind-css-design-systems","Mastering Tailwind CSS: From Utility Classes to Design Systems","Go beyond basic utility classes and learn how to build cohesive, maintainable design systems with Tailwind CSS.","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1555066931-4365d14bab8c?w=1200&q=80",257,10,"2026-07-21T06:02:49.268Z",{"id":21,"name":25,"avatarUrl":26},{"id":71,"slug":72,"title":73,"excerpt":74,"featuredImage":75,"viewCount":76,"readingTime":77,"publishedAt":78,"author":79},"50add5fc-4026-4267-b917-7f71ea9e35b0","complete-guide-vue3-composables","The Complete Guide to Vue 3 Composables","Understand the power of Vue 3's Composition API through practical, real-world composable patterns that you can use today.","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1517694712202-14dd9538aa97?w=1200&q=80",990,12,"2026-07-19T06:02:51.753Z",{"id":21,"name":25,"avatarUrl":26},{"data":81,"body":83,"toc":229},{"title":82,"description":82},"",{"type":84,"children":85},"root",[86,95,101,113,120,148,154,159,167,172,180,191,197,205,211,219,224],{"type":87,"tag":88,"props":89,"children":91},"element","h2",{"id":90},"teleport-render-anywhere-in-the-dom",[92],{"type":93,"value":94},"text","Teleport: Render Anywhere in the DOM",{"type":87,"tag":96,"props":97,"children":98},"p",{},[99],{"type":93,"value":100},"Teleport renders a component's template in a different DOM location while keeping it in the same logical component tree.",{"type":87,"tag":102,"props":103,"children":107},"pre",{"className":104,"code":105,"language":35,"meta":82,"style":106},"language-vue","\u003Ctemplate>\n  \u003Cdiv class=\"relative\">\n    \u003Cbutton @click=\"showModal = true\">Open Modal\u003C\u002Fbutton>\n\n    \u003C!-- Renders at document body, not inside this div -->\n    \u003CTeleport to=\"body\">\n      \u003Cdiv v-if=\"showModal\" class=\"fixed inset-0 z-50 flex items-center justify-center\">\n        \u003Cdiv class=\"fixed inset-0 bg-black\u002F50\" @click=\"showModal = false\" \u002F>\n        \u003Cdiv class=\"relative bg-white rounded-xl p-6 max-w-md w-full\">\n          \u003Ch2 class=\"text-lg font-bold\">Modal Title\u003C\u002Fh2>\n          \u003Cp>This renders at the body level, avoiding z-index issues.\u003C\u002Fp>\n          \u003Cbutton @click=\"showModal = false\">Close\u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002FTeleport>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup lang=\"ts\">\nconst showModal = ref(false)\n\u003C\u002Fscript>\n","undefined",[108],{"type":87,"tag":109,"props":110,"children":111},"code",{"__ignoreMap":82},[112],{"type":93,"value":105},{"type":87,"tag":114,"props":115,"children":117},"h3",{"id":116},"why-teleport",[118],{"type":93,"value":119},"Why Teleport?",{"type":87,"tag":121,"props":122,"children":123},"ul",{},[124,138,143],{"type":87,"tag":125,"props":126,"children":127},"li",{},[128,130,136],{"type":93,"value":129},"Avoids ",{"type":87,"tag":109,"props":131,"children":133},{"className":132},[],[134],{"type":93,"value":135},"overflow: hidden",{"type":93,"value":137}," clipping on parent containers",{"type":87,"tag":125,"props":139,"children":140},{},[141],{"type":93,"value":142},"Fixes z-index stacking context issues",{"type":87,"tag":125,"props":144,"children":145},{},[146],{"type":93,"value":147},"Keeps component logic colocated with its trigger",{"type":87,"tag":88,"props":149,"children":151},{"id":150},"suspense-async-component-coordination",[152],{"type":93,"value":153},"Suspense: Async Component Coordination",{"type":87,"tag":96,"props":155,"children":156},{},[157],{"type":93,"value":158},"Suspense shows fallback content while async components or setup functions resolve:",{"type":87,"tag":102,"props":160,"children":162},{"className":104,"code":161,"language":35,"meta":82,"style":106},"\u003Ctemplate>\n  \u003CSuspense>\n    \u003Ctemplate #default>\n      \u003CAsyncDashboard \u002F>\n    \u003C\u002Ftemplate>\n    \u003Ctemplate #fallback>\n      \u003CDashboardSkeleton \u002F>\n    \u003C\u002Ftemplate>\n  \u003C\u002FSuspense>\n\u003C\u002Ftemplate>\n",[163],{"type":87,"tag":109,"props":164,"children":165},{"__ignoreMap":82},[166],{"type":93,"value":161},{"type":87,"tag":96,"props":168,"children":169},{},[170],{"type":93,"value":171},"The async component:",{"type":87,"tag":102,"props":173,"children":175},{"className":104,"code":174,"language":35,"meta":82,"style":106},"\u003C!-- AsyncDashboard.vue -->\n\u003Cscript setup lang=\"ts\">\n\u002F\u002F This makes the component \"async\" — Suspense will wait for it\nconst { data: stats } = await useFetch('\u002Fapi\u002Fdashboard\u002Fstats')\nconst { data: activity } = await useFetch('\u002Fapi\u002Fdashboard\u002Factivity')\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv class=\"grid grid-cols-3 gap-4\">\n    \u003CStatCard v-for=\"stat in stats\" :key=\"stat.id\" v-bind=\"stat\" \u002F>\n  \u003C\u002Fdiv>\n  \u003CActivityFeed :items=\"activity\" \u002F>\n\u003C\u002Ftemplate>\n",[176],{"type":87,"tag":109,"props":177,"children":178},{"__ignoreMap":82},[179],{"type":93,"value":174},{"type":87,"tag":181,"props":182,"children":185},"callout",{"color":183,"icon":184},"info","i-lucide-loader",[186],{"type":87,"tag":96,"props":187,"children":188},{},[189],{"type":93,"value":190},"With Suspense, you can have multiple async components that all resolve before showing anything — no more cascading loading spinners.",{"type":87,"tag":88,"props":192,"children":194},{"id":193},"error-handling-with-suspense",[195],{"type":93,"value":196},"Error Handling with Suspense",{"type":87,"tag":102,"props":198,"children":200},{"className":104,"code":199,"language":35,"meta":82,"style":106},"\u003Cscript setup lang=\"ts\">\nconst error = ref\u003CError | null>(null)\n\nfunction onError(e: Error) {\n  error.value = e\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv v-if=\"error\" class=\"text-red-500\">\n    Something went wrong: {{ error.message }}\n  \u003C\u002Fdiv>\n\n  \u003CSuspense v-else @error=\"onError\">\n    \u003Ctemplate #default>\n      \u003CAsyncContent \u002F>\n    \u003C\u002Ftemplate>\n    \u003Ctemplate #fallback>\n      \u003CLoadingSpinner \u002F>\n    \u003C\u002Ftemplate>\n  \u003C\u002FSuspense>\n\u003C\u002Ftemplate>\n",[201],{"type":87,"tag":109,"props":202,"children":203},{"__ignoreMap":82},[204],{"type":93,"value":199},{"type":87,"tag":88,"props":206,"children":208},{"id":207},"combining-teleport-suspense",[209],{"type":93,"value":210},"Combining Teleport + Suspense",{"type":87,"tag":102,"props":212,"children":214},{"className":104,"code":213,"language":35,"meta":82,"style":106},"\u003Ctemplate>\n  \u003CTeleport to=\"#notification-area\">\n    \u003CSuspense>\n      \u003Ctemplate #default>\n        \u003CAsyncNotifications \u002F>\n      \u003C\u002Ftemplate>\n      \u003Ctemplate #fallback>\n        \u003CNotificationSkeleton \u002F>\n      \u003C\u002Ftemplate>\n    \u003C\u002FSuspense>\n  \u003C\u002FTeleport>\n\u003C\u002Ftemplate>\n",[215],{"type":87,"tag":109,"props":216,"children":217},{"__ignoreMap":82},[218],{"type":93,"value":213},{"type":87,"tag":96,"props":220,"children":221},{},[222],{"type":93,"value":223},"These built-in components solve real layout and async coordination problems. Use them to build smoother user experiences.",{"type":87,"tag":225,"props":226,"children":227},"style",{},[228],{"type":93,"value":82},{"title":82,"searchDepth":230,"depth":230,"links":231},2,[232,236,237,238],{"id":90,"depth":230,"text":94,"children":233},[234],{"id":116,"depth":235,"text":119},3,{"id":150,"depth":230,"text":153},{"id":193,"depth":230,"text":196},{"id":207,"depth":230,"text":210},{"success":4,"data":240},{"items":241,"pagination":297},[242,250,258,265,273,278,286,293],{"id":243,"name":244,"description":245,"parentId":14,"createdAt":246,"updatedAt":246,"parent":14,"children":247,"_count":248},"ai-future","AI & The Future","Artificial intelligence and emerging technology","2026-07-24T06:02:45.990Z",[],{"posts":249},1,{"id":251,"name":252,"description":253,"parentId":14,"createdAt":254,"updatedAt":254,"parent":14,"children":255,"_count":256},"tools-productivity","Tools & Productivity","Developer tools and workflow optimization","2026-07-24T06:02:45.712Z",[],{"posts":257},7,{"id":259,"name":260,"description":261,"parentId":14,"createdAt":262,"updatedAt":262,"parent":14,"children":263,"_count":264},"career","Career & Growth","Professional development for developers","2026-07-24T06:02:45.486Z",[],{"posts":235},{"id":266,"name":267,"description":268,"parentId":14,"createdAt":269,"updatedAt":269,"parent":14,"children":270,"_count":271},"opinion","Opinion & Analysis","Industry analysis and technical opinions","2026-07-24T06:02:45.272Z",[],{"posts":272},6,{"id":45,"name":46,"description":47,"parentId":14,"createdAt":274,"updatedAt":274,"parent":14,"children":275,"_count":276},"2026-07-24T06:02:44.965Z",[],{"posts":277},21,{"id":279,"name":280,"description":281,"parentId":14,"createdAt":282,"updatedAt":282,"parent":14,"children":283,"_count":284},"software-engineering","Software Engineering","Best practices, patterns, and principles","2026-07-24T06:02:44.689Z",[],{"posts":285},24,{"id":287,"name":288,"description":289,"parentId":14,"createdAt":290,"updatedAt":290,"parent":14,"children":291,"_count":292},"devops-cloud","DevOps & Cloud","Infrastructure, deployment, and cloud computing","2026-07-24T06:02:44.453Z",[],{"posts":272},{"id":41,"name":42,"description":43,"parentId":14,"createdAt":294,"updatedAt":294,"parent":14,"children":295,"_count":296},"2026-07-24T06:02:44.169Z",[],{"posts":285},{"page":249,"limit":15,"total":15,"totalPages":249,"hasNext":298,"hasPrev":298},false]