diff --git a/platform/ui/index.js b/platform/ui/index.js
index 2025cfb3b..66f9fad21 100644
--- a/platform/ui/index.js
+++ b/platform/ui/index.js
@@ -32,6 +32,7 @@ export {
DateRange,
Dialog,
EmptyStudies,
+ ErrorBoundary,
ExpandableToolbarButton,
ListMenu,
Icon,
diff --git a/platform/ui/package.json b/platform/ui/package.json
index 17619f2cf..601b7862d 100644
--- a/platform/ui/package.json
+++ b/platform/ui/package.json
@@ -42,6 +42,7 @@
"react-dnd": "^10.0.2",
"react-dnd-html5-backend": "^10.0.2",
"react-dnd-touch-backend": "^10.0.2",
+ "react-error-boundary": "2.2.x",
"react-dom": "16.11.0",
"react-modal": "^3.11.2",
"react-powerplug": "1.0.0",
diff --git a/platform/ui/src/components/ErrorBoundary/ErrorBoundary.jsx b/platform/ui/src/components/ErrorBoundary/ErrorBoundary.jsx
new file mode 100644
index 000000000..b75b35710
--- /dev/null
+++ b/platform/ui/src/components/ErrorBoundary/ErrorBoundary.jsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import { ErrorBoundary as ReactErrorBoundary } from 'react-error-boundary';
+import './ErrorFallback.css';
+
+const isProduction = process.env.NODE_ENV === 'production';
+
+const ErrorFallback = ({ error, componentStack, resetErrorBoundary }) => {
+ return (
+
+
Something went wrong.
+ {isProduction && (
+
Sorry, something went wrong there. Try again.
+ )}
+ {!isProduction &&
{error.message}}
+ {!isProduction &&
{componentStack}}
+
+ );
+};
+
+ErrorFallback.propTypes = {
+ resetErrorBoundary: PropTypes
+};
+
+const ErrorBoundary = ({
+ context = 'RCT',
+ onReset = () => { },
+ onError = () => { },
+ fallbackComponent,
+ children
+}) => {
+ const onErrorHandler = (error, componentStack) => {
+ console.error(`${context} Error Boundary`, error, componentStack);
+ onError(error, componentStack);
+ };
+
+ const onResetHandler = () => {
+ onReset();
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default ErrorBoundary;
diff --git a/platform/ui/src/components/ErrorBoundary/ErrorBoundary.mdx b/platform/ui/src/components/ErrorBoundary/ErrorBoundary.mdx
new file mode 100644
index 000000000..bb65df025
--- /dev/null
+++ b/platform/ui/src/components/ErrorBoundary/ErrorBoundary.mdx
@@ -0,0 +1,59 @@
+---
+name: Error Boundary
+menu: Data Display
+route: components/errorBoundary
+---
+
+import { Playground, Props } from 'docz';
+import { ErrorBoundary } from '@ohif/ui';
+
+# Error Boundary
+
+This component can be used to display a message or handle unhandled errors.
+
+## Import
+
+```javascript
+import { ErrorBoundary } from '@ohif/ui';
+```
+
+## Basic usage
+
+
+
+
+ {() => {
+ throw new Error('Error!');
+ return ;
+ }}
+
+
+
+
+## Custom error fallback
+
+
+ {() => {
+ const CustomFallback = ({ error, componentStack, resetErrorBoundary }) => {
+ return (
+
+
This is a custom fallback!
+
+ );
+ };
+ return (
+
+
+ {() => {
+ throw new Error('Error!');
+ return ;
+ }}
+
+
+ );
+ }}
+
+
+## Properties
+
+
diff --git a/platform/ui/src/components/ErrorBoundary/ErrorFallback.css b/platform/ui/src/components/ErrorBoundary/ErrorFallback.css
new file mode 100644
index 000000000..34d62ccf4
--- /dev/null
+++ b/platform/ui/src/components/ErrorBoundary/ErrorFallback.css
@@ -0,0 +1,21 @@
+.ErrorFallback {
+ padding: 10px;
+
+ &,
+ pre {
+ color: #7cc5e9;
+ }
+
+ p {
+ font-weight: bold;
+ }
+
+ span {
+ color: gray;
+ }
+
+ pre {
+ background-color: black;
+ border: none;
+ }
+}
diff --git a/platform/ui/src/components/ErrorBoundary/index.js b/platform/ui/src/components/ErrorBoundary/index.js
new file mode 100644
index 000000000..b54419282
--- /dev/null
+++ b/platform/ui/src/components/ErrorBoundary/index.js
@@ -0,0 +1,2 @@
+import ErrorBoundary from './ErrorBoundary';
+export default ErrorBoundary;
diff --git a/platform/ui/src/components/index.js b/platform/ui/src/components/index.js
index 04b5270cc..76d4f2729 100644
--- a/platform/ui/src/components/index.js
+++ b/platform/ui/src/components/index.js
@@ -3,6 +3,7 @@ import ButtonGroup from './ButtonGroup';
import DateRange from './DateRange';
import Dialog from './Dialog';
import EmptyStudies from './EmptyStudies';
+import ErrorBoundary from './ErrorBoundary';
import Icon from './Icon';
import IconButton from './IconButton';
import Input from './Input';
@@ -54,6 +55,7 @@ export {
DateRange,
Dialog,
EmptyStudies,
+ ErrorBoundary,
ExpandableToolbarButton,
ListMenu,
Icon,
diff --git a/yarn.lock b/yarn.lock
index a045e8f39..6b7ba067c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -18075,6 +18075,13 @@ react-dropzone@^10.1.7:
file-selector "^0.1.12"
prop-types "^15.7.2"
+react-error-boundary@2.2.x:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-2.2.3.tgz#34c8238012d3b4148cec47a1b3cec669d5206578"
+ integrity sha512-Jiaiu6CJ4ho3sMCVI7gg+O/JB5vlFFZGwlnpFBTCOSyheYRTzz+FhBMo7tfnCTB/ZR0LaMzAPGbZGrEzAOd0eg==
+ dependencies:
+ "@babel/runtime" "^7.9.6"
+
react-error-overlay@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-3.0.0.tgz#c2bc8f4d91f1375b3dad6d75265d51cd5eeaf655"