Skip to content
# ErrorBoundary ## Description BitErrorBoundary catches what the components inside it throw and renders a themed, accessible and recoverable error UI in their place, so one failure does not take the whole app down. It builds on Blazor's ErrorBoundary with a complete default UI, templates for every part, logging, callbacks, automatic recovery and a way in for the exceptions the renderer never sees. ## Parameters | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | AdditionalButtons | `RenderFragment?` | null | The extra content of the footer of the boundary's default error UI, rendered after the Refresh, Home and Recover buttons. A boundary that sets Footer never renders it. | | AutoFocus | `bool` | false | Moves the browser focus to the error UI as it appears, once per error, which then announces it in place of the alert. An error UI drawn by ErrorTemplate or ErrorContent has no element of the boundary's to move it to. | | Body | `RenderFragment?` | null | Alias of the ChildContent. | | ChildContent | `RenderFragment?` | null | The content the boundary renders and watches over while it has caught nothing. | | Class | `string?` | null | The CSS class of the root element of the boundary's error UI. | | Classes | `BitErrorBoundaryClassStyles?` | null | Custom CSS classes for different parts of the boundary's default error UI. | | CopiedText | `string?` | null | The text the Copy button carries while what it copied is still on the clipboard. Defaults to "Copied". | | CopyText | `string?` | null | The text of the Copy button. Defaults to "Copy details". | | Dir | `BitDir?` | null | The text directionality of the boundary's error UI. | | ErrorContent | `RenderFragment<Exception>?` | null | The inherited template of the error UI, receiving the caught exception alone. ErrorTemplate takes precedence over it. | | ErrorTemplate | `RenderFragment<BitErrorBoundaryContext>?` | null | The template of the error UI, receiving the caught exception along with the boundary's own Recover, Refresh and GoHome actions. | | ExceptionLabel | `string?` | null | The accessible name of the exception details block rendered by ShowException. Defaults to "Exception details", and an empty value drops the name and the region role with it. | | Footer | `RenderFragment?` | null | The footer content of the boundary, replacing the default Refresh, Home and Recover buttons while keeping the footer element they are laid out in. | | HeadingLevel | `int?` | null | The heading level (1 to 6) of the title, so it fits the outline of the page while its look stays the same. Defaults to 3. | | HideHomeButton | `bool` | false | Prevents rendering the Home button of the default error UI. | | HideIcon | `bool` | false | Prevents rendering the icon of the default error UI. | | HideRecoverButton | `bool` | false | Prevents rendering the Recover button of the default error UI. | | HideRefreshButton | `bool` | false | Prevents rendering the Refresh button of the default error UI. | | HomeText | `string?` | null | The text of the Home button. Defaults to "Home". | | HomeUrl | `string?` | null | The url of the home page for the Home button. Defaults to the site root. | | HtmlAttributes | `Dictionary<string, object>?` | null | The HTML attributes to be applied to the root element of the boundary's error UI. | | Icon | `BitIconInfo?` | null | The icon to display using custom CSS classes for external icon libraries. Takes precedence over IconName when both are set. | | IconName | `string?` | null | The name of the icon to render in place of the built-in illustration. | | IconTemplate | `RenderFragment?` | null | The template of the icon, replacing both the built-in illustration and IconName. | | Id | `string?` | null | The id of the root element of the boundary's error UI. | | MaximumErrorCount | `int` | 100 | The number of errors this boundary handles before it stops absorbing them and lets the next one through as fatal. Recovering resets the count. | | Message | `string?` | null | The message rendered under the title of the default error UI. Nothing is rendered while it has no value. | | NoLogging | `bool` | false | Prevents the boundary from logging the caught exception through the app's IErrorBoundaryLogger. | | OnError | `EventCallback<Exception>` | | The callback for when an error gets caught by the boundary, called before the error UI is rendered. | | OnRecover | `EventCallback<BitErrorBoundaryRecoverReason>` | | The callback for when the boundary leaves its errored state, receiving which of the routes back out of it was taken. | | RecoverKeys | `IEnumerable<object?>?` | null | The values that recover the boundary as they change. | | RecoverOnNavigation | `bool` | false | Recovers the boundary when the reader navigates to another location. | | RecoverText | `string?` | null | The text of the Recover button. Defaults to "Recover". | | RefreshText | `string?` | null | The text of the Refresh button. Defaults to "Refresh". | | ShowCopyButton | `bool` | false | Renders a Copy button in the footer of the default error UI, putting the exception's full text on the clipboard. | | ShowException | `bool` | false | Renders the full text of the caught exception, stack trace included, in a scrolling block that can receive the keyboard focus. | | Style | `string?` | null | The CSS style of the root element of the boundary's error UI. | | Styles | `BitErrorBoundaryClassStyles?` | null | Custom CSS styles for different parts of the boundary's default error UI. | | Title | `string?` | null | The title of the default error UI. Defaults to "Oops, Something went wrong...", and an empty value drops the heading. | | AriaLabel | `string?` | null | Gets or sets the accessible label for the component, used by assistive technologies. | | Class | `string?` | null | Gets or sets the CSS class name(s) to apply to the rendered element. | | Dir | `BitDir?` | null | Gets or sets the text directionality for the component's content. | | Disabled | `bool` | false | Gets or sets a value indicating whether the component is disabled and cannot respond to user interaction. | | ForceAnimation | `bool` | false | Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested. | | HtmlAttributes | `Dictionary<string, object>` | new Dictionary<string, object>() | Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters. An attribute written on the component wins over an entry of the same name. | | Id | `string?` | null | Gets or sets the unique identifier for the component's root element. | | Style | `string?` | null | Gets or sets the CSS style string to apply to the rendered element. | | TabIndex | `string?` | null | Gets or sets the tab order index for the component when navigating with the keyboard. | | Visibility | `BitVisibility` | BitVisibility.Visible | Gets or sets the visibility state (visible, hidden, or collapsed) of the component. | ## Public Members | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | CaughtException | `Exception?` | null | The exception the boundary is currently showing, or null while it has caught nothing. | | Capture | `void Capture(Exception exception)` | | Hands the boundary an exception that never passed through the renderer, putting it into exactly the state a caught one would. Call it on the renderer's synchronization context. | | CaptureAsync | `Task CaptureAsync(Exception exception)` | | Capture from a thread that is not the renderer's. | | Recover | `void Recover()` | | Clears the error and renders the boundary's content again, raising OnRecover. Never call it from rendering logic. | | Refresh | `void Refresh()` | | Reloads the current page in the browser, which is what the default UI's Refresh button does. | | GoHome | `void GoHome()` | | Navigates to HomeUrl, which is what the default UI's Home button does. | | UniqueId | `Guid` | Guid.NewGuid() | Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed. | | RootElement | `ElementReference` | | Gets the reference to the root HTML element associated with this component. | ## Enums ### BitErrorBoundaryRecoverReason Enum | Name | Value | Description | | :--- | :--- | :---------- | | Manual | 0 | The Recover button of the default error UI, the Recover action of an ErrorTemplate's context, or a call to the Recover method. | | Keys | 1 | One of the values of RecoverKeys differed from what the boundary last saw. | | Navigation | 2 | The reader navigated to another location while RecoverOnNavigation was set. | ### BitVisibility Enum | Name | Value | Description | | :--- | :--- | :---------- | | Visible | 0 | The content of the component is visible. | | Hidden | 1 | The content of the component is hidden, but the space it takes on the page remains (visibility:hidden). | | Collapsed | 2 | The component is hidden (display:none). | ### BitDir Enum | Name | Value | Description | | :--- | :--- | :---------- | | Ltr | 0 | Ltr (left to right) is to be used for languages that are written from the left to the right (like English). | | Rtl | 1 | Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic). | | Auto | 2 | Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element. | ## Sub Classes ### BitErrorBoundaryClassStyles Properties Nothing here reaches the boundary's own content: while no error has been caught the boundary renders its children and no element of its own. | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | Root | `string?` | null | Custom CSS classes/styles for the root element of the BitErrorBoundary's error UI. | | Header | `string?` | null | Custom CSS classes/styles for the header of the BitErrorBoundary, holding the icon, the title and the message, which is the part announced as the error appears. | | Icon | `string?` | null | Custom CSS classes/styles for the icon of the BitErrorBoundary. | | Title | `string?` | null | Custom CSS classes/styles for the title of the BitErrorBoundary. | | Message | `string?` | null | Custom CSS classes/styles for the message of the BitErrorBoundary. | | Exception | `string?` | null | Custom CSS classes/styles for the exception details block of the BitErrorBoundary. | | Footer | `string?` | null | Custom CSS classes/styles for the footer of the BitErrorBoundary, which holds a replaced Footer exactly as it holds the default buttons. | | RefreshButton | `BitButtonClassStyles?` | null | Custom CSS classes/styles for the Refresh button of the BitErrorBoundary. | | HomeButton | `BitButtonClassStyles?` | null | Custom CSS classes/styles for the Home button of the BitErrorBoundary. | | RecoverButton | `BitButtonClassStyles?` | null | Custom CSS classes/styles for the Recover button of the BitErrorBoundary. | | CopyButton | `BitButtonClassStyles?` | null | Custom CSS classes/styles for the Copy button of the BitErrorBoundary. | ### BitErrorBoundaryContext Properties What an ErrorTemplate is handed: the exception that was caught and the three ways out of it that the boundary's own error UI offers. | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | Exception | `Exception` | | The exception the boundary caught. | | Recover | `Action` | | Clears the error and renders the boundary's content again, exactly like the default UI's Recover button. | | Refresh | `Action` | | Reloads the current page in the browser, exactly like the default UI's Refresh button. | | GoHome | `Action` | | Navigates to HomeUrl, exactly like the default UI's Home button. | ## CSS Variables Public CSS custom properties read off the component's root. Set one on `:root` to restyle every instance, on any ancestor to restyle the ones inside it, or on the `Style` of one instance to restyle it and every instance nested inside it, which inherits the value too - a parameter changes one alone, as does the real CSS property on its `Style` / `Styles` when that property does not inherit (`opacity`); an inherited one (`color`, `font-family`) reaches the nested instances that do not set it themselves. | Name | Default Value | Description | | :--- | :------------ | :---------- | | `--bit-ErrorBoundary-background` | --bit-clr-bg-pri | Background of the error UI. | | `--bit-ErrorBoundary-border` | none | Border of the error UI. | | `--bit-ErrorBoundary-radius` | --bit-shp-radius-none | Corner radius of the error UI. | | `--bit-ErrorBoundary-padding` | spacing(3) | Padding of the error UI. | | `--bit-ErrorBoundary-gap` | spacing(2) | Room between the parts of the error UI. | | `--bit-ErrorBoundary-align` | center | start, center or end: aligns the parts, their text and the footer buttons together. | | `--bit-ErrorBoundary-icon-color` | --bit-clr-err | Color of the built-in illustration or of the icon. | | `--bit-ErrorBoundary-icon-size` | 64px (illustration) / --bit-siz-icon-lg (icon) | Size of the built-in illustration or of the icon. | | `--bit-ErrorBoundary-title-color` | --bit-clr-err-fg | Color of the title. | | `--bit-ErrorBoundary-message-color` | --bit-clr-fg-sec | Color of the message. | | `--bit-ErrorBoundary-message-max-width` | 560px | Longest line of the message. | | `--bit-ErrorBoundary-exception-background` | --bit-clr-bg-sec | Background of the exception details block. | | `--bit-ErrorBoundary-exception-color` | --bit-clr-fg-sec | Text color of the exception details block. | | `--bit-ErrorBoundary-exception-font-family` | --bit-tpg-font-family-mono | Font family of the exception details block. | | `--bit-ErrorBoundary-exception-max-height` | 320px | Tallest the exception details block gets before it scrolls. | ## Examples \n**Basic**: ```razor Throw an exception ``` ```csharp private void ThrowException() { throw new Exception("This is an exception!"); } ``` \n**Title & message**: ```razor Throw an exception ``` ```csharp private void ThrowException() { throw new Exception("This is an exception!"); } ``` \n**Icon**: ```razor Throw (IconName) Throw (IconTemplate) Throw (HideIcon) ``` ```csharp private void ThrowException() { throw new Exception("This is an exception!"); } ``` \n**Exception details**: ```razor Throw an exception ``` ```csharp private void ThrowException() { throw new Exception("This is an exception!"); } ``` \n**Actions**: ```razor Throw (AdditionalButtons) Report (@reportedCount) Throw (Footer)
Try again Report (@reportedCount)
``` ```csharp private int reportedCount; private BitErrorBoundary? footerBoundary; private void ThrowException() { throw new Exception("This is an exception!"); } ``` \n**Error template**: ```razor Throw an exception @error.Exception.Message
Try again
``` ```csharp private void ThrowException() { throw new Exception("This is an exception!"); } ``` \n**Events**: ```razor Throw an exception
Caught: @errorCount  |  Recovered: @recoverCount  |  Last error: @(lastError ?? "-")  |  Last recovery: @(lastRecoverReason?.ToString() ?? "-")
``` ```csharp private int errorCount; private int recoverCount; private string? lastError; private BitErrorBoundaryRecoverReason? lastRecoverReason; private void ThrowException() { throw new Exception("This is an exception!"); } private void HandleError(Exception exception) { errorCount++; lastError = exception.Message; } private void HandleRecover(BitErrorBoundaryRecoverReason reason) { recoverCount++; lastRecoverReason = reason; } ``` \n**Capture**: ```razor Capture through @@ref <_BitErrorBoundaryCaptureDemo /> ``` ```csharp private BitErrorBoundary? captureBoundary; private void CaptureFromReference() { captureBoundary?.Capture(new InvalidOperationException("Captured through a component reference.")); } ``` `_BitErrorBoundaryCaptureDemo.razor`: ```razor @* A component sitting inside a BitErrorBoundary. It never holds a reference to the boundary: the boundary cascades itself to its content, so a cascading parameter is all it takes to hand it an exception the renderer would never have seen. *@ Capture through the cascade @code { [CascadingParameter] private BitErrorBoundary? errorBoundary { get; set; } private void Load() { // Nothing awaits this task, so nothing routes what it throws to the boundary above - which is // exactly the case Capture exists for. _ = Task.Run(async () => { await Task.Delay(500); try { throw new InvalidOperationException("The data could not be loaded in the background."); } catch (Exception ex) { if (errorBoundary is not null) { // Off the renderer's thread, so CaptureAsync rather than Capture. await errorBoundary.CaptureAsync(ex); } } }); } } ``` \n**Automatic recovery**: ```razor Throw (RecoverKeys) Record 1 Record 2 Record 3 Throw (RecoverOnNavigation) Navigate ``` ```csharp [Inject] private NavigationManager NavManager { get; set; } = default!; private int navigateCount; private int selectedRecord = 1; private void ThrowException() { throw new Exception("This is an exception!"); } private void NavigateInPlace() { navigateCount++; NavManager.NavigateTo($"/components/errorboundary?nav={navigateCount}#example9"); } ``` \n**Accessibility**: ```razor Throw an exception ``` ```csharp private void ThrowException() { throw new Exception("This is an exception!"); } ``` \n**Cascading parameters**: ```razor Throw (cascaded) Throw (own Title) ``` ```csharp private readonly BitErrorBoundaryParams[] errorBoundaryParams = [ new() { HideIcon = true, HideHomeButton = true, HideRefreshButton = true, Title = "This widget could not be loaded", Message = "The rest of the page still works.", RecoverText = "Reload the widget", } ]; private void ThrowException() { throw new Exception("This is an exception!"); } ``` \n**External Icons**: ```razor Throw an exception Throw an exception ``` ```csharp private void ThrowException() { throw new Exception("This is an exception!"); } ``` \n**Style & Class**: ```razor Throw (Styles) Throw (Classes) Throw (CSS variables) ``` ```csharp private void ThrowException() { throw new Exception("This is an exception!"); } ``` `BitErrorBoundaryDemo.razor.scss`: ```scss ::deep { .custom-erb { border-radius: 0.5rem; background: linear-gradient(180deg, #3e0f0f, transparent) #000; } .custom-erb-ttl { color: #ff9d9d; letter-spacing: 0.05rem; } .custom-erb-btn { color: #fff; border-radius: 1rem; border-color: #8f0101; transition: background-color 1s; background: linear-gradient(90deg, #d10000, transparent) #8f0101; } .custom-erb-btn:hover { color: #fff; border-color: #8f0101; background-color: #8f0101; } } ``` \n**RTL**: ```razor
ایجاد خطا
``` ```csharp private void ThrowException() { throw new Exception("This is an exception!"); } ```