Picture this: You've just deployed your shiny new Vue application. Everything looks perfect in your dev environment. Then your phone buzzes with a message from a user: "Hey, the dashboard is completely blank." We've all been there, and it's not a great feeling.
What if there was a way to contain errors so they only affect the specific component that's misbehaving, while the rest of your application keeps running smoothly? Enter Error Boundary components – your application's safety net for catching errors before they ruin the user experience.
In this guide, we'll dive into the world of error boundaries in Vue: what they are, why they're a game-changer for your applications, how to build your own, and where to find ready-made solutions to save yourself some time. Let's turn those frustrating error scenarios into manageable, graceful failures!
Think of error boundaries as specialized bodyguards for your components. They catch JavaScript errors in their descendant component tree and smoothly display a fallback UI instead of letting your entire application crash and burn. They're the difference between "the whole app is down!" and "hmm, that one widget isn't loading, but everything else works fine."
Let's be honest – errors happen to the best of us. Here's why error boundaries should be your new best friends:
To use error boundaries effectively, you typically wrap potentially problematic components or sections of your application with an error boundary component. Here's a basic usage pattern:
<template>
<div>
<ErrorBoundary>
<RiskyFeatureComponent />
<template #error="{ error, reset }">
<div class="error-container">
<p>Something went wrong with this feature.</p>
<button @click="reset">Try Again</button>
</div>
</template>
</ErrorBoundary>
<!-- The rest of your app continues to function -->
<AnotherComponent />
</div>
</template>
In this pattern, if RiskyFeatureComponent
throws an error, the error boundary captures it and renders the fallback UI defined in the #error
slot instead. Meanwhile, AnotherComponent
continues to function normally.
Vue core doesn’t ship with an error boundary component but you can build your own simple and effective error boundary component using the Composition API and the built-in onErrorCaptured
lifecycle hook.
<!--ErrorBoundary.vue-->
<script setup lang="ts">
// create an reactive container to store the potential error
const error = ref();
// using Vue's build in lifecycle hook
// listen for errors from components passed to the default slot
onErrorCaptured((err) => {
// set the reactive error container to the thrown error
error.value = err;
// return false to prevent error from bubbling further
// (this is optional, if you have a top level error reporter catching errors
// you probably don't want to do this.
// Alternatively you could report your errors in the boundary and prevent bubble
return false;
});
// create a way to clear the error
function clearError() {
error.value = null;
}
// provide the error and the clear error function to the slot
// for use in consuming component to display messaging
// and clear the error
const slotProps = computed(() => {
if (!error.value) return {};
return { error, clearError };
});
// if there's an error show the error slot, otherwise show the default slot
const slotName = computed(() => (error.value ? "error" : "default"));
</script>
<template>
<slot :name="slotName" v-bind="slotProps"></slot>
</template>
Now that you know what an error boundary is, how to use one, and even have the code to build your own, you might go a little overboard. Here are some tips for using error boundaries effectively.
Let's look at a practical example of using error boundaries in a dashboard with multiple independent widgets:
<template>
<div class="dashboard">
<h1>User Dashboard</h1>
<div class="widgets-container">
<!-- Each widget has its own error boundary -->
<ErrorBoundary>
<UserStatsWidget :userId="userId" />
<template #error>
<WidgetErrorState widget-name="User Statistics" />
</template>
</ErrorBoundary>
<ErrorBoundary>
<RecentActivityWidget :userId="userId" />
<template #error>
<WidgetErrorState widget-name="Recent Activity" />
</template>
</ErrorBoundary>
<ErrorBoundary>
<NotificationsWidget :userId="userId" />
<template #error>
<WidgetErrorState widget-name="Notifications" />
</template>
</ErrorBoundary>
</div>
</div>
</template>
With this approach, if the UserStatsWidget
fails to load or throws an error during rendering, only that widget will show an error state while the rest of the dashboard continues to function.
Finally, if you'd prefer not to build your own error boundary component or want a more robust solution than the component above, a quick google search provides several pre-built solutions.
stop-propagation
prop to prevent bubbling but takes a “fallback” component instance as a prop instead of supporting an error slot.Error boundaries are a little intimidating on first introduction but really they are a simple and highly practical tool for gracefully handling errors in Vue.js. With the knowledge gained from this article you’re ready to wield ErrorBoundaries in your Vue apps for a better DX and UX.
Want to go beyond error boundaries and dive even further into Vue.js error handling?
Check out our comprehensive course Handling Errors in Vue Like a Pro where we dive deeper into error boundaries and all the other error-fighting techniques that will make your applications rock-solid.
Our goal is to be the number one source of Vue.js knowledge for all skill levels. We offer the knowledge of our industry leaders through awesome video courses for a ridiculously low price.
More than 200.000 users have already joined us. You are welcome too!
© All rights reserved. Made with ❤️ by BitterBrains, Inc.