diff --git a/frontend/src/components/common/async-loading-boundary/__snapshots__/async-loading-boundary.test.tsx.snap b/frontend/src/components/common/async-loading-boundary/__snapshots__/async-loading-boundary.test.tsx.snap
new file mode 100644
index 000000000..8079c47b1
--- /dev/null
+++ b/frontend/src/components/common/async-loading-boundary/__snapshots__/async-loading-boundary.test.tsx.snap
@@ -0,0 +1,41 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Async loading boundary shows a waiting spinner if loading 1`] = `
+<div>
+  <div
+    class="m-3 d-flex align-items-center justify-content-center"
+  >
+    <i
+      class="fa  fa-spinner fa-spin "
+    />
+  </div>
+</div>
+`;
+
+exports[`Async loading boundary shows an error if error is given with loading 1`] = `
+<div>
+  <div
+    class="fade alert alert-danger show"
+    role="alert"
+  >
+    common.errorWhileLoading
+  </div>
+</div>
+`;
+
+exports[`Async loading boundary shows an error if error is given without loading 1`] = `
+<div>
+  <div
+    class="fade alert alert-danger show"
+    role="alert"
+  >
+    common.errorWhileLoading
+  </div>
+</div>
+`;
+
+exports[`Async loading boundary shows the children if not loading and no error 1`] = `
+<div>
+  children
+</div>
+`;
diff --git a/frontend/src/components/common/async-loading-boundary/__snapshots__/custom-async-loading-boundary.test.tsx.snap b/frontend/src/components/common/async-loading-boundary/__snapshots__/custom-async-loading-boundary.test.tsx.snap
new file mode 100644
index 000000000..c01a834d0
--- /dev/null
+++ b/frontend/src/components/common/async-loading-boundary/__snapshots__/custom-async-loading-boundary.test.tsx.snap
@@ -0,0 +1,25 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Custom error async loading boundary shows a waiting spinner if loading 1`] = `
+<div>
+  wait
+</div>
+`;
+
+exports[`Custom error async loading boundary shows an error if error is given with loading 1`] = `
+<div>
+  error
+</div>
+`;
+
+exports[`Custom error async loading boundary shows an error if error is given without loading 1`] = `
+<div>
+  error
+</div>
+`;
+
+exports[`Custom error async loading boundary shows the children if not loading and no error 1`] = `
+<div>
+  children
+</div>
+`;
diff --git a/frontend/src/components/common/async-loading-boundary/async-loading-boundary.test.tsx b/frontend/src/components/common/async-loading-boundary/async-loading-boundary.test.tsx
new file mode 100644
index 000000000..56e2ee685
--- /dev/null
+++ b/frontend/src/components/common/async-loading-boundary/async-loading-boundary.test.tsx
@@ -0,0 +1,48 @@
+/*
+ * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import { mockI18n } from '../../markdown-renderer/test-utils/mock-i18n'
+import { AsyncLoadingBoundary } from './async-loading-boundary'
+import { render } from '@testing-library/react'
+
+describe('Async loading boundary', () => {
+  beforeAll(() => mockI18n())
+
+  it('shows the children if not loading and no error', () => {
+    const view = render(
+      <AsyncLoadingBoundary loading={false} componentName={'test'}>
+        children
+      </AsyncLoadingBoundary>
+    )
+    expect(view.container).toMatchSnapshot()
+  })
+
+  it('shows a waiting spinner if loading', () => {
+    const view = render(
+      <AsyncLoadingBoundary loading={true} componentName={'test'}>
+        children
+      </AsyncLoadingBoundary>
+    )
+    expect(view.container).toMatchSnapshot()
+  })
+
+  it('shows an error if error is given without loading', () => {
+    const view = render(
+      <AsyncLoadingBoundary loading={false} error={new Error('error')} componentName={'test'}>
+        children
+      </AsyncLoadingBoundary>
+    )
+    expect(view.container).toMatchSnapshot()
+  })
+
+  it('shows an error if error is given with loading', () => {
+    const view = render(
+      <AsyncLoadingBoundary loading={true} error={new Error('error')} componentName={'test'}>
+        children
+      </AsyncLoadingBoundary>
+    )
+    expect(view.container).toMatchSnapshot()
+  })
+})
diff --git a/frontend/src/components/common/async-loading-boundary.tsx b/frontend/src/components/common/async-loading-boundary/async-loading-boundary.tsx
similarity index 71%
rename from frontend/src/components/common/async-loading-boundary.tsx
rename to frontend/src/components/common/async-loading-boundary/async-loading-boundary.tsx
index fc2fd7761..336e3897b 100644
--- a/frontend/src/components/common/async-loading-boundary.tsx
+++ b/frontend/src/components/common/async-loading-boundary/async-loading-boundary.tsx
@@ -3,9 +3,10 @@
  *
  * SPDX-License-Identifier: AGPL-3.0-only
  */
-import { WaitSpinner } from './wait-spinner/wait-spinner'
-import type { PropsWithChildren, ReactNode } from 'react'
-import React, { Fragment } from 'react'
+import { WaitSpinner } from '../wait-spinner/wait-spinner'
+import { CustomAsyncLoadingBoundary } from './custom-async-loading-boundary'
+import type { PropsWithChildren } from 'react'
+import React, { Fragment, useMemo } from 'react'
 import { Alert } from 'react-bootstrap'
 import { Trans, useTranslation } from 'react-i18next'
 
@@ -13,7 +14,6 @@ export interface AsyncLoadingBoundaryProps {
   loading: boolean
   error?: Error | boolean
   componentName: string
-  errorComponent?: ReactNode
 }
 
 /**
@@ -30,22 +30,27 @@ export const AsyncLoadingBoundary: React.FC<PropsWithChildren<AsyncLoadingBounda
   loading,
   error,
   componentName,
-  errorComponent,
   children
 }) => {
   useTranslation()
-  if (error !== undefined && error !== false) {
-    if (errorComponent) {
-      return <Fragment>{errorComponent}</Fragment>
-    }
-    return (
+
+  const errorComponent = useMemo(() => {
+    return error ? (
       <Alert variant={'danger'}>
         <Trans i18nKey={'common.errorWhileLoading'} values={{ name: componentName }} />
       </Alert>
+    ) : (
+      <Fragment></Fragment>
     )
-  } else if (loading) {
-    return <WaitSpinner />
-  } else {
-    return <Fragment>{children}</Fragment>
-  }
+  }, [componentName, error])
+
+  return (
+    <CustomAsyncLoadingBoundary
+      loading={loading}
+      error={error}
+      errorComponent={errorComponent}
+      loadingComponent={<WaitSpinner />}>
+      {children}
+    </CustomAsyncLoadingBoundary>
+  )
 }
diff --git a/frontend/src/components/common/async-loading-boundary/custom-async-loading-boundary.test.tsx b/frontend/src/components/common/async-loading-boundary/custom-async-loading-boundary.test.tsx
new file mode 100644
index 000000000..8b15ca5d4
--- /dev/null
+++ b/frontend/src/components/common/async-loading-boundary/custom-async-loading-boundary.test.tsx
@@ -0,0 +1,56 @@
+/*
+ * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import { mockI18n } from '../../markdown-renderer/test-utils/mock-i18n'
+import { CustomAsyncLoadingBoundary } from './custom-async-loading-boundary'
+import { render } from '@testing-library/react'
+
+describe('Custom error async loading boundary', () => {
+  beforeAll(() => mockI18n())
+
+  it('shows the children if not loading and no error', () => {
+    const view = render(
+      <CustomAsyncLoadingBoundary loading={false} errorComponent={'error'} loadingComponent={'wait'}>
+        children
+      </CustomAsyncLoadingBoundary>
+    )
+    expect(view.container).toMatchSnapshot()
+  })
+
+  it('shows a waiting spinner if loading', () => {
+    const view = render(
+      <CustomAsyncLoadingBoundary loading={true} errorComponent={'error'} loadingComponent={'wait'}>
+        children
+      </CustomAsyncLoadingBoundary>
+    )
+    expect(view.container).toMatchSnapshot()
+  })
+
+  it('shows an error if error is given without loading', () => {
+    const view = render(
+      <CustomAsyncLoadingBoundary
+        loading={false}
+        error={new Error('error')}
+        errorComponent={'error'}
+        loadingComponent={'wait'}>
+        children
+      </CustomAsyncLoadingBoundary>
+    )
+    expect(view.container).toMatchSnapshot()
+  })
+
+  it('shows an error if error is given with loading', () => {
+    const view = render(
+      <CustomAsyncLoadingBoundary
+        loading={true}
+        error={new Error('error')}
+        errorComponent={'error'}
+        loadingComponent={'wait'}>
+        children
+      </CustomAsyncLoadingBoundary>
+    )
+    expect(view.container).toMatchSnapshot()
+  })
+})
diff --git a/frontend/src/components/common/async-loading-boundary/custom-async-loading-boundary.tsx b/frontend/src/components/common/async-loading-boundary/custom-async-loading-boundary.tsx
new file mode 100644
index 000000000..738feae53
--- /dev/null
+++ b/frontend/src/components/common/async-loading-boundary/custom-async-loading-boundary.tsx
@@ -0,0 +1,42 @@
+/*
+ * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import type { PropsWithChildren, ReactNode } from 'react'
+import React, { Fragment } from 'react'
+import { useTranslation } from 'react-i18next'
+
+export interface CustomErrorAsyncLoadingBoundaryProps {
+  loading: boolean
+  error?: Error | boolean
+  errorComponent: ReactNode
+  loadingComponent: ReactNode
+}
+
+/**
+ * Indicates that a component currently loading or an error occurred.
+ * It's meant to be used in combination with useAsync from react-use.
+ *
+ * @param loading Indicates that the component is currently loading. Setting this will show a spinner instead of the children.
+ * @param error Indicates that an error occurred during the loading process. Setting this to any non-null value will show an error message instead of the children.
+ * @param componentName The name of the component that is currently loading. It will be shown in the error message.
+ * @param errorComponent Optional component that will be used in case of an error instead of the default alert message.
+ * @param children The child {@link ReactElement elements} that are only shown if the component isn't in loading or error state
+ */
+export const CustomAsyncLoadingBoundary: React.FC<PropsWithChildren<CustomErrorAsyncLoadingBoundaryProps>> = ({
+  loading,
+  error,
+  errorComponent,
+  loadingComponent,
+  children
+}) => {
+  useTranslation()
+  if (error) {
+    return <Fragment>{errorComponent}</Fragment>
+  } else if (loading) {
+    return <Fragment>{loadingComponent}</Fragment>
+  } else {
+    return <Fragment>{children}</Fragment>
+  }
+}
diff --git a/frontend/src/components/common/note-loading-boundary/note-loading-boundary.tsx b/frontend/src/components/common/note-loading-boundary/note-loading-boundary.tsx
index 779e8e7a5..082eff093 100644
--- a/frontend/src/components/common/note-loading-boundary/note-loading-boundary.tsx
+++ b/frontend/src/components/common/note-loading-boundary/note-loading-boundary.tsx
@@ -5,11 +5,12 @@
  */
 import { LoadingScreen } from '../../application-loader/loading-screen/loading-screen'
 import { CommonErrorPage } from '../../error-pages/common-error-page'
+import { CustomAsyncLoadingBoundary } from '../async-loading-boundary/custom-async-loading-boundary'
 import { ShowIf } from '../show-if/show-if'
 import { CreateNonExistingNoteHint } from './create-non-existing-note-hint'
 import { useLoadNoteFromServer } from './hooks/use-load-note-from-server'
 import type { PropsWithChildren } from 'react'
-import React, { Fragment, useEffect } from 'react'
+import React, { useEffect, useMemo } from 'react'
 
 /**
  * Loads the note identified by the note-id in the URL.
@@ -18,16 +19,17 @@ import React, { Fragment, useEffect } from 'react'
  *
  * @param children The react elements that will be shown when the loading was successful.
  */
-export const NoteLoadingBoundary: React.FC<PropsWithChildren<unknown>> = ({ children }) => {
-  const [{ error, loading }, loadNoteFromServer] = useLoadNoteFromServer()
+export const NoteLoadingBoundary: React.FC<PropsWithChildren> = ({ children }) => {
+  const [{ error, loading, value }, loadNoteFromServer] = useLoadNoteFromServer()
 
   useEffect(() => {
     loadNoteFromServer()
   }, [loadNoteFromServer])
 
-  if (loading) {
-    return <LoadingScreen />
-  } else if (error) {
+  const errorComponent = useMemo(() => {
+    if (error === undefined) {
+      return <></>
+    }
     return (
       <CommonErrorPage titleI18nKey={`${error.message}.title`} descriptionI18nKey={`${error.message}.description`}>
         <ShowIf condition={error.message === 'api.note.notFound'}>
@@ -35,7 +37,15 @@ export const NoteLoadingBoundary: React.FC<PropsWithChildren<unknown>> = ({ chil
         </ShowIf>
       </CommonErrorPage>
     )
-  } else {
-    return <Fragment>{children}</Fragment>
-  }
+  }, [error, loadNoteFromServer])
+
+  return (
+    <CustomAsyncLoadingBoundary
+      loading={loading || !value}
+      error={error}
+      errorComponent={errorComponent}
+      loadingComponent={<LoadingScreen />}>
+      {children}
+    </CustomAsyncLoadingBoundary>
+  )
 }
diff --git a/frontend/src/components/common/user-avatar/user-avatar-for-username.tsx b/frontend/src/components/common/user-avatar/user-avatar-for-username.tsx
index 0c3a9a170..a778fecbb 100644
--- a/frontend/src/components/common/user-avatar/user-avatar-for-username.tsx
+++ b/frontend/src/components/common/user-avatar/user-avatar-for-username.tsx
@@ -5,7 +5,7 @@
  */
 import { getUser } from '../../../api/users'
 import type { UserInfo } from '../../../api/users/types'
-import { AsyncLoadingBoundary } from '../async-loading-boundary'
+import { AsyncLoadingBoundary } from '../async-loading-boundary/async-loading-boundary'
 import type { UserAvatarProps } from './user-avatar'
 import { UserAvatar } from './user-avatar'
 import React from 'react'
diff --git a/frontend/src/components/editor-page/document-bar/revisions/revision-list.tsx b/frontend/src/components/editor-page/document-bar/revisions/revision-list.tsx
index f89281294..c85b73561 100644
--- a/frontend/src/components/editor-page/document-bar/revisions/revision-list.tsx
+++ b/frontend/src/components/editor-page/document-bar/revisions/revision-list.tsx
@@ -5,7 +5,7 @@
  */
 import { getAllRevisions } from '../../../../api/revisions'
 import { useApplicationState } from '../../../../hooks/common/use-application-state'
-import { AsyncLoadingBoundary } from '../../../common/async-loading-boundary'
+import { AsyncLoadingBoundary } from '../../../common/async-loading-boundary/async-loading-boundary'
 import { RevisionListEntry } from './revision-list-entry'
 import { DateTime } from 'luxon'
 import React, { useMemo } from 'react'
diff --git a/frontend/src/components/editor-page/document-bar/revisions/revision-viewer.tsx b/frontend/src/components/editor-page/document-bar/revisions/revision-viewer.tsx
index 23509b294..03c2a9804 100644
--- a/frontend/src/components/editor-page/document-bar/revisions/revision-viewer.tsx
+++ b/frontend/src/components/editor-page/document-bar/revisions/revision-viewer.tsx
@@ -6,7 +6,7 @@
 import { getRevision } from '../../../../api/revisions'
 import { useApplicationState } from '../../../../hooks/common/use-application-state'
 import { useDarkModeState } from '../../../../hooks/common/use-dark-mode-state'
-import { AsyncLoadingBoundary } from '../../../common/async-loading-boundary'
+import { AsyncLoadingBoundary } from '../../../common/async-loading-boundary/async-loading-boundary'
 import { invertUnifiedPatch } from './invert-unified-patch'
 import { Optional } from '@mrdrogdrog/optional'
 import { applyPatch, parsePatch } from 'diff'
diff --git a/frontend/src/components/intro-page/intro-custom-content.tsx b/frontend/src/components/intro-page/intro-custom-content.tsx
index 391934be7..83e357b1b 100644
--- a/frontend/src/components/intro-page/intro-custom-content.tsx
+++ b/frontend/src/components/intro-page/intro-custom-content.tsx
@@ -4,7 +4,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 import { Logger } from '../../utils/logger'
-import { AsyncLoadingBoundary } from '../common/async-loading-boundary'
+import { AsyncLoadingBoundary } from '../common/async-loading-boundary/async-loading-boundary'
 import { RenderIframe } from '../editor-page/renderer-pane/render-iframe'
 import { RendererType } from '../render-page/window-post-message-communicator/rendering-message'
 import { fetchFrontPageContent } from './requests'
diff --git a/frontend/src/extensions/extra-integrations/abcjs/abc-frame.tsx b/frontend/src/extensions/extra-integrations/abcjs/abc-frame.tsx
index 9fdbde262..10da79e35 100644
--- a/frontend/src/extensions/extra-integrations/abcjs/abc-frame.tsx
+++ b/frontend/src/extensions/extra-integrations/abcjs/abc-frame.tsx
@@ -3,7 +3,7 @@
  *
  * SPDX-License-Identifier: AGPL-3.0-only
  */
-import { AsyncLoadingBoundary } from '../../../components/common/async-loading-boundary'
+import { AsyncLoadingBoundary } from '../../../components/common/async-loading-boundary/async-loading-boundary'
 import { ShowIf } from '../../../components/common/show-if/show-if'
 import { WaitSpinner } from '../../../components/common/wait-spinner/wait-spinner'
 import type { CodeProps } from '../../../components/markdown-renderer/replace-components/code-block-component-replacer'
diff --git a/frontend/src/extensions/extra-integrations/flowchart/flowchart.tsx b/frontend/src/extensions/extra-integrations/flowchart/flowchart.tsx
index 6fc8171fb..8e0434abc 100644
--- a/frontend/src/extensions/extra-integrations/flowchart/flowchart.tsx
+++ b/frontend/src/extensions/extra-integrations/flowchart/flowchart.tsx
@@ -4,7 +4,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 import fontStyles from '../../../../global-styles/variables.module.scss'
-import { AsyncLoadingBoundary } from '../../../components/common/async-loading-boundary'
+import { AsyncLoadingBoundary } from '../../../components/common/async-loading-boundary/async-loading-boundary'
 import { ShowIf } from '../../../components/common/show-if/show-if'
 import type { CodeProps } from '../../../components/markdown-renderer/replace-components/code-block-component-replacer'
 import { useDarkModeState } from '../../../hooks/common/use-dark-mode-state'
diff --git a/frontend/src/extensions/extra-integrations/graphviz/graphviz-frame.tsx b/frontend/src/extensions/extra-integrations/graphviz/graphviz-frame.tsx
index d0b03c130..0233fee58 100644
--- a/frontend/src/extensions/extra-integrations/graphviz/graphviz-frame.tsx
+++ b/frontend/src/extensions/extra-integrations/graphviz/graphviz-frame.tsx
@@ -3,7 +3,7 @@
  *
  * SPDX-License-Identifier: AGPL-3.0-only
  */
-import { AsyncLoadingBoundary } from '../../../components/common/async-loading-boundary'
+import { AsyncLoadingBoundary } from '../../../components/common/async-loading-boundary/async-loading-boundary'
 import { ShowIf } from '../../../components/common/show-if/show-if'
 import type { CodeProps } from '../../../components/markdown-renderer/replace-components/code-block-component-replacer'
 import { cypressId } from '../../../utils/cypress-attribute'
diff --git a/frontend/src/extensions/extra-integrations/highlighted-code-fence/highlighted-code.tsx b/frontend/src/extensions/extra-integrations/highlighted-code-fence/highlighted-code.tsx
index f08b01cd8..8b4cc81d5 100644
--- a/frontend/src/extensions/extra-integrations/highlighted-code-fence/highlighted-code.tsx
+++ b/frontend/src/extensions/extra-integrations/highlighted-code-fence/highlighted-code.tsx
@@ -3,7 +3,7 @@
  *
  * SPDX-License-Identifier: AGPL-3.0-only
  */
-import { AsyncLoadingBoundary } from '../../../components/common/async-loading-boundary'
+import { AsyncLoadingBoundary } from '../../../components/common/async-loading-boundary/async-loading-boundary'
 import { CopyToClipboardButton } from '../../../components/common/copyable/copy-to-clipboard-button/copy-to-clipboard-button'
 import { cypressAttribute, cypressId } from '../../../utils/cypress-attribute'
 import { testId } from '../../../utils/test-id'
diff --git a/frontend/src/extensions/extra-integrations/vega-lite/vega-lite-chart.tsx b/frontend/src/extensions/extra-integrations/vega-lite/vega-lite-chart.tsx
index 57369c161..58fe1f839 100644
--- a/frontend/src/extensions/extra-integrations/vega-lite/vega-lite-chart.tsx
+++ b/frontend/src/extensions/extra-integrations/vega-lite/vega-lite-chart.tsx
@@ -3,7 +3,7 @@
  *
  * SPDX-License-Identifier: AGPL-3.0-only
  */
-import { AsyncLoadingBoundary } from '../../../components/common/async-loading-boundary'
+import { AsyncLoadingBoundary } from '../../../components/common/async-loading-boundary/async-loading-boundary'
 import { ShowIf } from '../../../components/common/show-if/show-if'
 import type { CodeProps } from '../../../components/markdown-renderer/replace-components/code-block-component-replacer'
 import { Logger } from '../../../utils/logger'
diff --git a/frontend/src/pages/new.tsx b/frontend/src/pages/new.tsx
index f64a647d7..938427f5a 100644
--- a/frontend/src/pages/new.tsx
+++ b/frontend/src/pages/new.tsx
@@ -4,7 +4,8 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 import { createNote } from '../api/notes'
-import { AsyncLoadingBoundary } from '../components/common/async-loading-boundary'
+import { LoadingScreen } from '../components/application-loader/loading-screen/loading-screen'
+import { CustomAsyncLoadingBoundary } from '../components/common/async-loading-boundary/custom-async-loading-boundary'
 import { Redirect } from '../components/common/redirect'
 import { CommonErrorPage } from '../components/error-pages/common-error-page'
 import { useSingleStringUrlParameter } from '../hooks/common/use-single-string-url-parameter'
@@ -22,10 +23,10 @@ export const NewNotePage: NextPage = () => {
   }, [newContent])
 
   return (
-    <AsyncLoadingBoundary
+    <CustomAsyncLoadingBoundary
       loading={loading}
-      componentName={'NewNotePage'}
       error={error}
+      loadingComponent={<LoadingScreen />}
       errorComponent={
         <CommonErrorPage
           titleI18nKey={'errors.noteCreationFailed.title'}
@@ -33,7 +34,7 @@ export const NewNotePage: NextPage = () => {
         />
       }>
       {value ? <Redirect to={`/n/${value.metadata.primaryAddress}`} /> : null}
-    </AsyncLoadingBoundary>
+    </CustomAsyncLoadingBoundary>
   )
 }