When the UI Breaks: Designing Error Boundaries and Failure UX in Vue
Vue error handling is not just about catching failures, but about designing what users experience when things breakâusing error boundaries for UI recovery and global handlers for monitoring.
At some point, something will break.
Not maybe. Not rarely.
Inevitably.
A property you thought existed⌠doesnât.
An API response comes back slightly different.
A component tries to render something that isnât there.
And suddenly, your UI stops behaving like an interfaceâŚ
and starts behaving like a broken promise.
The real problem isnât that errors happen.
Itâs what the user experiences when they do.
The Moment Everything Stops
Imagine this:
<p>{{ user.profile.name }}</p>It looks harmless.
Until one day, the API responds with:
user = {}Now profile is undefined.
And when Vue tries to evaluate user.profile.nameâŚ
everything stops.
The render fails.
The UI freezes.
And the user is left staring at a screen that no longer responds.
Not because the app crashed completely.
But because one part of it couldnât continue.
Catching the Error Isnât the Same as Recovering
Vue gives you a global safety net:
app.config.errorHandler = (err, instance, info) => {
console.error(err)
}So yes â the error is caught.
You can log it. Track it. Send it somewhere.
But hereâs the subtle truth:
Catching the error doesnât fix the UI.
By the time this handler runs, the render has already failed.
So while you know something went wrongâŚ
the user is still stuck in a broken interface.
The Shift: From Debugging to Experience
At this point, the question changes.
Itâs no longer:
âHow do I catch errors?â
It becomes:
âWhat should the user see when things go wrong?â
Because a frozen screen is not an acceptable answer.
Enter the Error Boundary
Vue has a quieter feature that solves this more gracefully.
errorCaptured(err, instance, info) {
return false
}It doesnât look like much.
But it changes everything.
Instead of reacting after the failureâŚ
it intercepts the error within the component tree itself.
And that gives you control.
Replacing Failure With Something Intentional
You can wrap your app in a boundary:
<AppErrorBoundary>
<router-view />
</AppErrorBoundary>And inside that boundary:
- if everything works â render normally
- if something breaks â show fallback UI
A modal. A message. A safe screen.
Not a frozen page.
Not silence.
Something intentional.
A Different Kind of UI State
We often think about UI in three states:
- loading
- success
- empty
But real applications have a fourth state thatâs often ignored:
failure.
Not just technical failure.
User-visible failure.
And if you donât design for itâŚ
the browser will design it for you.
Usually as a blank or broken screen.
Global vs Local Responsibility
There are two layers to handling errors.
At the global level:
app.config.errorHandler = (err) => {
sendToMonitoring(err)
}This is about awareness.
Logging. Tracking. Observing.
It answers:
âWhat went wrong?â
At the component level:
errorCaptured(err) {
this.hasError = true
return false
}This is about experience.
Fallback UI. Recovery. Navigation.
It answers:
âWhat should the user do now?â
Both are necessary.
But they solve different problems.
Giving Users a Way Out
Once you accept that failure is part of the systemâŚ
you start designing exits.
Instead of trapping users in a broken page, you give them options:
- go back to dashboard
- retry
- reload
- navigate somewhere safe
Because the worst experience is not an error.
Itâs being stuck.
Not All Errors Are the Same
A missing property is not the same as:
- a network failure
- an expired session
- a permission issue
Yet many apps treat all errors the same way.
A generic message.
A generic modal.
But if you look closer, each type of failure suggests a different response:
- network issue â retry
- auth issue â redirect to login
- developer bug â fallback + report
So error handling slowly becomes something else.
Not just engineering.
But product design.
A Subtle but Important Realization
At first, error handling feels like a safety net.
Something you add just in case.
But over time, you realize:
Errors are not edge cases.
They are part of the systemâs behavior.
And the way your app handles themâŚ
is part of the user experience.
A Shift in Perspective
Instead of asking:
âHow do I prevent every error?â
You start asking:
âWhat happens when prevention fails?â
Because it will.
And when it does, your app has two choices:
- leave the user in confusion
- or guide them somewhere safe
And that choice is not technical.
Itâs intentional.