diff --git a/src/api/element.ts b/src/api/element.ts
index 4b4d66582be7ff77a64f47c408a012054ed1e498..56c57eed0165228c30b611121470c2e9ae7375a5 100644
--- a/src/api/element.ts
+++ b/src/api/element.ts
@@ -98,13 +98,20 @@ export const deleteElements = unique(({ corpus, ...params }: ElementDestroyParam
 export const deleteElementChildren = unique(({ id, ...params }: ElementChildrenDestroyParameters) => axios.delete(`/elements/${id}/children/`, { params }))
 
 export interface ElementNeighbor {
-  position: number,
-  element: ElementLight,
-  parents: ElementLight[]
+  ordering: number
+  previous: ElementLight | null
+  next: ElementLight | null
+  /**
+   * List of parent elements, ending with the most direct parent of this element.
+   *
+   * When the path in the database refers to elements that no longer exist ("ghost elements"), this path might contain `null` values.
+   * An error notification should be displayed to the user to help in troubleshooting those paths.
+   */
+  path: (ElementLight | null)[]
 }
 
 // List an element neighbors
-export const listElementNeighbors = unique(async (id: UUID): Promise<PageNumberPagination<ElementNeighbor>> => (await axios.get(`/elements/${id}/neighbors/`)).data)
+export const listElementNeighbors = unique(async (id: UUID): Promise<ElementNeighbor[]> => (await axios.get(`/elements/${id}/neighbors/`)).data)
 
 // Retrieve an element.
 export const retrieveElement = unique(async (id: UUID): Promise<Element> => (await axios.get(`/element/${id}/`)).data)
diff --git a/src/components/Element/AnnotationPanel.vue b/src/components/Element/AnnotationPanel.vue
index 0998b49c1732fef1fb712273bac7b2fdb5948097..466b687403c086fc489ba7d2fa59ab39021c3e17 100644
--- a/src/components/Element/AnnotationPanel.vue
+++ b/src/components/Element/AnnotationPanel.vue
@@ -84,7 +84,7 @@ export default {
     }
   },
   computed: {
-    ...mapState('elements', ['elements', 'neighbors']),
+    ...mapState('elements', ['elements']),
     ...mapState('annotation', ['tool']),
     element () {
       return this.elements[this.elementId]
diff --git a/src/components/Element/DetailsPanel.vue b/src/components/Element/DetailsPanel.vue
index f090cce8aad9aa6cf5b4a1216dba0710a1d6f70e..20d9a7961c3fe58f6b3a39c6b135326b462bcade 100644
--- a/src/components/Element/DetailsPanel.vue
+++ b/src/components/Element/DetailsPanel.vue
@@ -73,7 +73,7 @@
 
 <script>
 import { mapState, mapGetters } from 'vuex'
-import { corporaMixin } from '@/mixins.js'
+import { corporaMixin } from '@/mixins'
 
 import DropdownContent from '@/components/DropdownContent.vue'
 import MLClassSelect from '@/components/MLClassSelect.vue'
@@ -113,7 +113,7 @@ export default {
     transcriptionModal: false
   }),
   computed: {
-    ...mapState('elements', ['elements', 'transcriptions', 'neighbors']),
+    ...mapState('elements', ['elements', 'transcriptions']),
     ...mapState('process', ['workerVersions', 'workers']),
     ...mapState('classification', ['hasMlClasses']),
     ...mapGetters('elements', {
@@ -145,12 +145,6 @@ export default {
     },
     metadata () {
       return (this.element && this.element.metadata) || []
-    },
-    firstParentId () {
-      // Returns the first parent element of this element. Used to redirect to a parent when deleting the element
-      const neighbor = this.neighbors?.[this.elementId]?.results?.find(n => n.element?.id === this.elementId)
-      // Prevent errors on null parents since ListElementNeighbors can return null parents for paths with 'ghost elements'
-      return [...neighbor?.parents ?? []].reverse().find(parent => parent !== null)?.id
     }
   },
   methods: {
diff --git a/src/components/Element/ElementHeader.vue b/src/components/Element/ElementHeader.vue
index 010f3c80466239bbb1f48a25f0ec3e7c5b92ae7f..efa296d265bd8c338c6f599db99df73e7c06f3f1 100644
--- a/src/components/Element/ElementHeader.vue
+++ b/src/components/Element/ElementHeader.vue
@@ -1,226 +1,105 @@
 <template>
-  <div>
-    <div :class="{ 'has-shadow': !subHeader }">
-      <div class="elt-header is-flex">
-        <template v-if="element && !loading">
-          <div class="columns has-items-centered">
-            <div class="is-flex column is-narrow is-hidden-mobile">
-              <template v-if="!subHeader">
-                <div
-                  v-if="morePaths > 0"
-                  :title="morePaths + ' more path' + (morePaths > 1 ? 's' : '') + ' for this element'"
-                >
-                  <a
-                    v-on:click="toggleShowPaths"
-                    class="navbar-link"
-                  >
-                    <div class="tag is-link">
-                      +{{ morePaths }}
-                    </div>
-                  </a>
-                </div>
-              </template>
-            </div>
-            <div class="is-flex column">
-              <nav class="breadcrumb is-flex has-vpadding">
-                <ul>
-                  <li>
-                    <router-link :to="corpusLink" class="has-text-weight-semibold">
-                      {{ truncateShort(element.corpus.name) }}
-                    </router-link>
-                  </li>
-                  <template v-if="currentNeighbor">
-                    <li
-                      v-for="parent in currentNeighbor.parents"
-                      :key="parent.id"
-                    >
-                      <span class="is-flex has-hpadding">
-                        <span class="has-text-grey" :title="typeName(parent.type)">
-                          {{ truncateShort(typeName(parent.type)) }}&nbsp;
-                        </span>
-                        <router-link
-                          class="is-paddingless"
-                          :to="elementLink(parent.id)"
-                          :title="parent.name"
-                        >
-                          {{ truncateLong(parent.name) }}
-                        </router-link>
-                      </span>
-                    </li>
-                  </template>
-                  <li>
-                    <span class="is-flex has-hpadding has-items-centered">
-                      <span class="is-flex has-text-grey" :title="typeName(element.type)">
-                        {{ truncateShort(typeName(element.type)) }}&nbsp;
-                      </span>
-                      <EditableName
-                        :instance="element"
-                        :enabled="isVerified && canWrite(corpus)"
-                        dispatch="elements/patch"
-                        class="has-text-weight-bold"
-                      />
-                    </span>
-                  </li>
-                </ul>
-              </nav>
-            </div>
-
-            <div class="is-flex column is-narrow" v-if="currentNeighbor">
-              <div>
-                <router-link
-                  :to="pathLink(previous)"
-                  :class="{ 'disabled': !previous }"
-                >
-                  <i class="icon-arrow-left"></i>
-                </router-link>
-                {{ currentNeighbor.position + 1 }}
-                <router-link
-                  :to="pathLink(next)"
-                  :class="{ 'disabled': !next }"
-                >
-                  <i class="icon-arrow-right"></i>
-                </router-link>
+  <div class="has-shadow">
+    <div class="elt-header is-flex">
+      <div class="columns mx-0 is-align-items-center" v-if="element">
+        <div class="column p-0 is-narrow is-hidden-mobile">
+          <div
+            v-if="morePaths > 0"
+            :title="morePaths + ' more path' + (morePaths > 1 ? 's' : '') + ' for this element'"
+          >
+            <a
+              v-on:click="toggleAllPaths(null)"
+              class="navbar-link"
+            >
+              <div class="tag is-link">
+                +{{ morePaths }}
               </div>
-            </div>
-
-            <HeaderActions v-if="!subHeader" :corpus-id="corpusId" :element-id="element.id" />
+            </a>
           </div>
-        </template>
-        <span v-else class="has-vpadding">Loading…</span>
-      </div>
-      <transition name="paths">
-        <div v-if="element && showPaths && !subHeader">
-          <ElementHeader
-            v-for="(e, index) in similarElementNeighbors.slice(1)"
-            :key="index"
-            :element="element"
-            :neighbor="e"
-            :sub-header="true"
-          />
         </div>
-      </transition>
+
+        <ElementPath
+          class="column"
+          :element="element"
+          :neighbor="sortedNeighbors[0]"
+          :loading="loading"
+          keyboard-shortcuts
+        />
+
+        <HeaderActions :corpus-id="corpusId" :element-id="element.id" />
+      </div>
+      <span v-else class="loader py-2"></span>
     </div>
+    <transition name="paths">
+      <div class="px-3" v-if="element && displayAllPaths">
+        <ElementPath
+          v-for="(neighbor, index) in sortedNeighbors.slice(1)"
+          :key="index"
+          :element="element"
+          :neighbor="neighbor"
+        />
+      </div>
+    </transition>
   </div>
 </template>
 
 <script>
-import { mapState, mapGetters } from 'vuex'
-import { isEqual } from 'lodash'
-import Mousetrap from 'mousetrap'
-import { truncateMixin, corporaMixin } from '@/mixins.js'
-import EditableName from '@/components/EditableName.vue'
+import { mapState as mapVuexState } from 'vuex'
+import { mapState, mapActions } from 'pinia'
+import { corporaMixin } from '@/mixins'
 import HeaderActions from '@/components/HeaderActions.vue'
-import ElementHeader from './ElementHeader'
+import ElementPath from './ElementPath'
+import { useDisplayStore } from '@/stores'
 
 export default {
   mixins: [
-    truncateMixin,
     corporaMixin
   ],
-  name: 'ElementHeader',
   props: {
     element: {
       type: Object,
       required: true
-    },
-    neighbor: {
-      type: Object,
-      default: null
-    },
-    /*
-     * Displays path breadcrumb and neighbors navigation only
-     * This property is used in recursive display of multiple paths
-     */
-    subHeader: {
-      type: Boolean,
-      default: false
     }
   },
   components: {
     HeaderActions,
-    EditableName,
-    ElementHeader
+    ElementPath
   },
   data: () => ({
-    showPaths: false,
     loading: false
   }),
-  mounted () {
-    this.showPaths = sessionStorage.getItem('showPaths') === 'true'
-    if (!this.subHeader) {
-      Mousetrap.bind('ctrl+left', () => {
-        if (this.previous) this.$router.push(this.pathLink(this.previous))
-      })
-      Mousetrap.bind('ctrl+right', () => {
-        if (this.next) this.$router.push(this.pathLink(this.next))
-      })
-    }
-  },
   computed: {
-    ...mapGetters('auth', ['isAdmin', 'isVerified', 'hasFeature']),
-    ...mapState('elements', ['childrenPagination']),
-    ...mapState('elements', { neighborsState: 'neighbors' }),
+    ...mapVuexState('elements', {
+      elementNeighbors (state) {
+        return state.neighbors[this.element?.id] ?? []
+      }
+    }),
+    ...mapState(useDisplayStore, ['displayAllPaths']),
     corpusId () {
       return this.element?.corpus?.id ?? null
     },
-    corpusLink () {
-      const route = {
-        name: 'navigation',
-        params: { corpusId: this.element.corpus.id }
-      }
-      return route
-    },
-    allElementNeighbors () {
-      return this.neighborsState[this.element.id]?.results
-    },
-    similarElementNeighbors () {
-      /*
-       * Filters neighbors from the state to list only items concerning the current element
-       * Allows to display the different paths concerning the main element in recursive instances of the ElementHeader
-       */
-      if (!this.element?.id || !this.allElementNeighbors) return []
-      const eltNeighbors = this.allElementNeighbors.filter(n => n.element.id === this.element.id)
+    sortedNeighbors () {
+      if (!this.element?.id || !this.elementNeighbors?.length) return []
 
+      const eltNeighbors = [...this.elementNeighbors]
       // If we know the parent folder, display paths containing that parent at the closest position
       if (eltNeighbors.length > 1 && this.fromFolderId) {
         eltNeighbors.sort(
-          neighbor => {
+          ({ path }) => {
             /*
              * Sort paths depending on the parent's position: 0 if a direct parent, 1 if grandparent, Infinite if not found
              * As parents are listed from top to bottom, look for the parent index from the end of the array (closer to the element)
              */
-            const parents = [...neighbor.parents].reverse()
-            const index = parents.findIndex(elt => elt.id === this.fromFolderId)
-            return index === -1 ? Infinity : index
+            const index = path.findLastIndex(elt => elt.id === this.fromFolderId)
+            return index === -1 ? Infinity : path.length - 1 - index
           }
         )
       }
+
       return eltNeighbors
     },
-    currentNeighbor () {
-      // Current neighbor result, containing its path (ordered parents IDs) and position within siblings
-      if (this.subHeader && this.neighbor) {
-        // Return neighbor property for recursive sub-headers
-        if (this.neighbor.parents.some(p => p === null)) return null
-        return this.neighbor
-      }
-      if (!this.similarElementNeighbors.length) return null
-      return this.similarElementNeighbors[0]
-    },
-    previous () {
-      if (!this.currentNeighbor) return null
-      const previous = this.allElementNeighbors.find(n => isEqual(n.parents, this.currentNeighbor.parents) && n.position < this.currentNeighbor.position)
-      if (!previous) return null
-      else return previous.element.id
-    },
-    next () {
-      if (!this.currentNeighbor) return null
-      const next = this.allElementNeighbors.find(n => isEqual(n.parents, this.currentNeighbor.parents) && n.position > this.currentNeighbor.position)
-      if (!next) return null
-      else return next.element.id
-    },
     morePaths () {
-      return this.similarElementNeighbors.length - 1
+      return this.elementNeighbors.length - 1
     },
     fromFolderId () {
       // Query parameter allowing to order path corresponding to the navigation scheme
@@ -228,39 +107,9 @@ export default {
     }
   },
   methods: {
-    getDirectParent (eltId = null) {
-      /*
-       * Returns the direct parent of a specific element in the current path
-       * In case elementId is null, returns the first parent in the path
-       */
-      const parents = this.currentNeighbor?.parents
-      if (!parents || parents.length === 0) return
-      if (!eltId) return parents[parents.length - 1]
-
-      const eltIndex = parents.findIndex(elt => elt.id === eltId)
-      if (eltIndex <= 0) return
-      return parents[eltIndex - 1]
-    },
-    elementLink (eltId, routeName = 'element-details', parent = null) {
-      /* Returns a link to a route (default to element's details) from an element ID */
-      if (!eltId) return {}
-      const from = parent?.id || this.getDirectParent(eltId)?.id
-      return {
-        name: routeName,
-        params: { id: eltId },
-        query: { from }
-      }
-    },
-    pathLink (eltId) {
-      /* Returns a link to same route but with a different ID parameter */
-      return this.elementLink(eltId, this.$route.name, this.getDirectParent())
-    },
-    toggleShowPaths () {
-      this.showPaths = !this.showPaths
-      sessionStorage.setItem('showPaths', this.showPaths)
-    },
+    ...mapActions(useDisplayStore, ['toggleAllPaths']),
     async load () {
-      if (!this.element || this.subHeader || this.allElementNeighbors) return
+      if (!this.element || this.elementNeighbors.length) return
       this.loading = true
       try {
         await this.$store.dispatch('elements/listNeighbors', { id: this.element.id })
@@ -279,13 +128,6 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-.disabled {
-  pointer-events: none;
-  opacity: 0.4;
-}
-.has-items-centered > * {
-  align-items: center;
-}
 .elt-header {
   & > .columns {
     width: 100%;
@@ -300,12 +142,6 @@ export default {
 .has-shadow {
   box-shadow: 0.1rem 0.1rem 0.6rem lightgray;
 }
-.has-hpadding {
-  padding: 0 0.75em;
-}
-.has-vpadding {
-  padding: .5rem 0 .5rem 0
-}
 .paths-enter-active {
   transition: all .4s;
 }
diff --git a/src/components/Element/ElementPath.vue b/src/components/Element/ElementPath.vue
new file mode 100644
index 0000000000000000000000000000000000000000..8dda5e6c3116f60bd4db52781fe89bc8e6d99794
--- /dev/null
+++ b/src/components/Element/ElementPath.vue
@@ -0,0 +1,169 @@
+<template>
+  <div class="columns m-0 is-align-items-center">
+    <div class="column p-0">
+      <nav class="breadcrumb py-2">
+        <ul>
+          <li>
+            <router-link :to="{ name: 'navigation', params: { corpusId } }" class="has-text-weight-semibold">
+              {{ truncateShort(corpus.name) }}
+            </router-link>
+          </li>
+
+          <template v-if="neighbor">
+            <li
+              v-for="(parent, index) in neighbor.path"
+              :key="index"
+            >
+              <!-- Handle nulls when a path refers to an element that no longer exists -->
+              <span class="is-italic pr-3" v-if="parent === null">
+                Deleted element
+              </span>
+              <template v-else>
+                <span class="pl-3 has-text-grey" :title="typeName(parent.type)">
+                  {{ truncateShort(typeName(parent.type)) }}&nbsp;
+                </span>
+                <router-link
+                  class="pl-0 pr-3 parent-name"
+                  :to="elementLink(parent.id)"
+                  :title="parent.name"
+                >
+                  {{ truncateLong(parent.name) }}
+                </router-link>
+              </template>
+            </li>
+          </template>
+
+          <li v-if="loading">
+            <span class="loader mx-3"></span>
+          </li>
+
+          <li>
+            <span class="is-flex is-align-items-center px-3">
+              <span class="has-text-grey" :title="typeName(element.type)">
+                {{ truncateShort(typeName(element.type)) }}&nbsp;
+              </span>
+              <EditableName
+                :instance="element"
+                :enabled="isVerified && canWrite(corpus)"
+                dispatch="elements/patch"
+                class="has-text-weight-bold"
+              />
+            </span>
+          </li>
+        </ul>
+      </nav>
+    </div>
+
+    <div class="column is-narrow p-0" v-if="neighbor">
+      <router-link
+        :to="pathLink(neighbor.previous?.id)"
+        :class="{ 'disabled': neighbor.previous === null }"
+      >
+        <i class="icon-arrow-left"></i>
+      </router-link>
+
+      {{ neighbor.ordering + 1 }}
+
+      <router-link
+        :to="pathLink(neighbor.next?.id)"
+        :class="{ 'disabled': neighbor.next === null }"
+      >
+        <i class="icon-arrow-right"></i>
+      </router-link>
+    </div>
+  </div>
+</template>
+
+<script>
+import Mousetrap from 'mousetrap'
+import { mapState } from 'vuex'
+import { corporaMixin, truncateMixin } from '@/mixins'
+import EditableName from '@/components/EditableName.vue'
+
+export default {
+  mixins: [
+    truncateMixin,
+    corporaMixin
+  ],
+  props: {
+    element: {
+      type: Object,
+      required: true,
+      validator: element => typeof element === 'object' && element.id && element.corpus?.id && element.type
+    },
+    neighbor: {
+      type: Object,
+      default: null
+    },
+    loading: {
+      type: Boolean,
+      default: false
+    },
+    /**
+     * Whether to assign the Ctrl+Left and Ctrl+Right shortcuts to browsing the previous and next elements on this path.
+     */
+    keyboardShortcuts: {
+      type: Boolean,
+      default: false
+    }
+  },
+  components: {
+    EditableName
+  },
+  mounted () {
+    if (this.keyboardShortcuts) {
+      Mousetrap.bind('ctrl+left', () => {
+        if (this.neighbor?.previous) this.$router.push(this.pathLink(this.neighbor.previous.id))
+      })
+      Mousetrap.bind('ctrl+right', () => {
+        if (this.neighbor?.next) this.$router.push(this.pathLink(this.neighbor.next.id))
+      })
+    }
+  },
+  beforeUnmount () {
+    if (this.keyboardShortcuts) {
+      Mousetrap.unbind('ctrl+left')
+      Mousetrap.unbind('ctrl+right')
+    }
+  },
+  computed: {
+    ...mapState('auth', ['isVerified']),
+    corpusId () {
+      return this.element.corpus.id
+    }
+  },
+  methods: {
+    elementLink (eltId, routeName = 'element-details', parent = null) {
+      /* Returns a link to a route (default to element's details) from an element ID */
+      if (!eltId) return {}
+      return {
+        name: routeName,
+        params: { id: eltId },
+        query: { from: parent?.id }
+      }
+    },
+    /**
+     * Returns a link to same route but for another element ID.
+     * When available, this path's direct parent ID will be used as the ?from= query parameter.
+     */
+    pathLink (eltId) {
+      return this.elementLink(eltId, this.$route.name, this.neighbor?.path[this.neighbor?.path?.length - 1])
+    }
+  }
+}
+</script>
+
+<style>
+a.disabled {
+  pointer-events: none;
+  opacity: 0.4;
+}
+@media screen and (max-width: 1200px) {
+  a.parent-name {
+    display: inline;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    max-width: 30ch;
+  }
+}
+</style>
diff --git a/src/components/Element/PanelHeader.vue b/src/components/Element/PanelHeader.vue
index 921f454b54295f09fa1b449cb8d1b89874e2817c..93608a15196750560ba8937f55a4db9d2cb0a294 100644
--- a/src/components/Element/PanelHeader.vue
+++ b/src/components/Element/PanelHeader.vue
@@ -111,11 +111,12 @@ export default {
     editionModal: false
   }),
   computed: {
-    ...mapState('elements', ['elements', 'neighbors']),
+    ...mapState('elements', ['elements']),
     ...mapState('annotation', {
       annotationEnabled: 'enabled'
     }),
     ...mapGetters('elements', {
+      firstParentId: 'firstParentId',
       // canWrite and canAdmin are already defined in corporaMixin
       canWriteElement: 'canWrite',
       canAdminElement: 'canAdmin'
@@ -136,12 +137,6 @@ export default {
     mainElementId () {
       const routeParams = this.$route && this.$route.params
       return routeParams && routeParams.id
-    },
-    firstParentId () {
-      // Returns the first parent element of this element. Used to redirect to a parent when deleting the element
-      const neighbor = this.neighbors?.[this.elementId]?.results?.find(n => n.element?.id === this.elementId)
-      // Prevent errors on null parents since ListElementNeighbors can return null parents for paths with 'ghost elements'
-      return [...neighbor?.parents ?? []].reverse().find(parent => parent !== null)?.id
     }
   },
   methods: {
@@ -159,7 +154,7 @@ export default {
       let newRoute = null
       if (this.elementId === this.mainElementId) {
         // When deleting the main element, redirect to the first parent element or the corpus.
-        if (this.firstParentId) newRoute = { name: 'element-details', params: { id: this.firstParentId } }
+        if (this.firstParentId(this.elementId)) newRoute = { name: 'element-details', params: { id: this.firstParentId(this.elementId) } }
         else newRoute = { name: 'navigation', params: { corpusId: this.corpusId } }
       }
 
diff --git a/src/components/HeaderActions.vue b/src/components/HeaderActions.vue
index fa92bcdddfd5fecb96f7f972c920eee24053daf5..38e33ab5dcfc957554d398c5d35084baacad1da1 100644
--- a/src/components/HeaderActions.vue
+++ b/src/components/HeaderActions.vue
@@ -1,5 +1,5 @@
 <template>
-  <div class="is-flex column is-narrow">
+  <div class="column is-narrow is-flex-shrink-1 px-0">
     <div class="dropdown is-right is-hoverable">
       <div class="dropdown-trigger">
         <a class="navbar-link">
@@ -534,6 +534,7 @@ export default {
       'hasFeature'
     ]),
     ...mapVuexGetters('elements', {
+      firstParentId: 'firstParentId',
       // canWrite and canAdmin are already defined in corporaMixin
       canWriteElement: 'canWrite',
       canAdminElement: 'canAdmin'
@@ -569,19 +570,12 @@ export default {
     totalChildrenCount () {
       return this.elementId && this.childrenPagination[this.elementId]?.count
     },
-    firstParentId () {
-      // Returns the first parent element of this element. Used to redirect to a parent when deleting the element
-      if (!this.elementId || !this.neighbors[this.elementId]?.results) return null
-      const neighbor = this.neighbors[this.elementId].results.find(n => n.element && n.element.id === this.elementId)
-      // Prevent errors on null parents since ListElementNeighbors can return null parents for paths with 'ghost elements'
-      return [...(neighbor.parents ?? [])].reverse().find(parent => parent !== null)?.id
-    },
     elementDirectParents () {
-      if (!this.elementId || !this.neighbors[this.elementId]?.results) return null
+      if (!this.elementId || !Array.isArray(this.neighbors[this.elementId])) return null
       // Fetch all direct parents of this element.
-      const firstParents = this.neighbors[this.elementId].results
-        .filter(({ element, parents }) => element?.id === this.elementId && parents?.length > 0)
-        .map(({ parents }) => parents[parents.length - 1])
+      const firstParents = this.neighbors[this.elementId]
+        .filter(({ path }) => path?.length > 0)
+        .map(({ path }) => path[path.length - 1])
       // Prevent returning duplicated parents by filtering out identical objects.
       return firstParents.filter((parent, index, parents) => parents.findIndex(p => (p.id === parent.id)) === index)
     },
@@ -707,8 +701,8 @@ export default {
          * When removing a corpus, redirect to the corpora list page.
          */
         if (this.elementId) {
-          if (this.firstParentId) {
-            this.$router.push({ name: 'element-details', params: { id: this.firstParentId } })
+          if (this.firstParentId(this.elementId)) {
+            this.$router.push({ name: 'element-details', params: { id: this.firstParentId(this.elementId) } })
           } else {
             this.$router.push({ name: 'navigation', params: { corpusId: this.corpusId } })
           }
@@ -732,8 +726,8 @@ export default {
         this.moveModal = false
 
         // Redirect to the first parent element when available, otherwise redirect to the element's corpus.
-        if (this.firstParentId) {
-          this.$router.push({ name: 'element-details', params: { id: this.firstParentId } })
+        if (this.firstParentId(this.elementId)) {
+          this.$router.push({ name: 'element-details', params: { id: this.firstParentId(this.elementId) } })
         } else {
           this.$router.push({ name: 'navigation', params: { corpusId: this.corpusId } })
         }
diff --git a/src/store/elements.js b/src/store/elements.js
index 2320f2dbbeee4b7bc060e31cce652713226bdee2..125c73edc0043af870df842de4c526d82e06b4c3 100644
--- a/src/store/elements.js
+++ b/src/store/elements.js
@@ -1,4 +1,4 @@
-import { assign, clone, merge } from 'lodash'
+import { assign, clone, merge, zip } from 'lodash'
 import * as api from '@/api'
 import { ELEMENT_LIST_MAX_AUTO_PAGES } from '@/config'
 import { errorParser } from '@/helpers'
@@ -12,7 +12,9 @@ export const initialState = () => ({
    * { [elementId]: id[] }
    */
   parents: {},
-  // { [id]: neighbors }
+  /**
+   * @type {{ [elementId: import('@/types').UUID]: import('@/api').ElementNeighbor[] }}
+   */
   neighbors: {},
   // { [id]: { children: { count: … } }
   links: {},
@@ -192,8 +194,8 @@ export const mutations = {
   addNeighbors (state, { element, neighbors }) {
     const newNeighbors = clone(neighbors)
     let nullParentError = false
-    if (newNeighbors && Array.isArray(newNeighbors.results)) {
-      newNeighbors.results.forEach(neighbor => {
+    if (newNeighbors && Array.isArray(newNeighbors)) {
+      newNeighbors.forEach(neighbor => {
         /*
          * Detect and remove null values in each neighbor element's parents.
          * When the path array in ElementPath has IDs that point to elements that no longer exist,
@@ -201,8 +203,8 @@ export const mutations = {
          * We will still update the state, but throw an error after committing to show a notification
          * and get an explicit alert on Sentry.
          */
-        if (!nullParentError && neighbor.parents.some(parent => parent === null)) nullParentError = true
-        neighbor.parents = neighbor.parents.filter(parent => parent !== null)
+        if (!nullParentError && neighbor.path.some(parent => parent === null)) nullParentError = true
+        neighbor.path = neighbor.path.filter(parent => parent !== null)
       })
     }
     state.neighbors = {
@@ -578,6 +580,24 @@ export const getters = {
   },
   canAdmin: state => id => {
     return (state.elements[id]?.rights ?? []).includes('admin')
+  },
+  /**
+   * Returns the first parent element of this element. Used to redirect to a parent when deleting the element
+   * @type {import('@/types').UUID}
+   */
+  firstParentId: state => id => {
+    // Find all known paths for the element and reverse them so they start with the most direct parents
+    const allPaths = state.neighbors?.[id]?.map(({ path }) => [...path].reverse()) ?? []
+    /*
+     * Prevent errors on null parents since ListElementNeighbors can return null parents for paths with 'ghost elements':
+     * find the first defined parent in any path, starting with the most direct parents.
+     * This uses zip().flat(1) so that we can look for all the direct parents in all paths first, then the grandparents, etc.
+     * instead of going through each ancestry line one by one.
+     * Lodash's zip() operates like itertools.zip_longest and not like the standard Python zip(),
+     * so it can return arrays with undefined values if all paths are not the same length,
+     * so we have to handle both null and undefined.
+     */
+    return zip(...allPaths).flat(1).find(parent => parent)?.id
   }
 }
 
diff --git a/src/stores/display.ts b/src/stores/display.ts
index 0e683e4a7ccc4039bb75d4d30943ced23c3d7e27..6fd1c188dd54ab85926cb6a9894e1b157edb4cbd 100644
--- a/src/stores/display.ts
+++ b/src/stores/display.ts
@@ -38,6 +38,11 @@ interface State {
    */
   displayElementClasses: boolean
 
+  /**
+   * Whether to expand the element header to show all of the element's paths.
+   */
+  displayAllPaths: boolean
+
   /**
    * Whether to display elements as a table in navigation views,
    * instead of thumbnails
@@ -87,6 +92,11 @@ const getScreenSize = (): ScreenSize => {
   return { width: window.innerWidth, height: window.innerHeight }
 }
 
+const getShowPaths = (): boolean => {
+  if (typeof window === 'undefined' || !window.sessionStorage) return false
+  return window.sessionStorage.getItem('showPaths') === 'true'
+}
+
 export const useDisplayStore = defineStore('display', {
   state: (): State => ({
     screen: getScreenSize(),
@@ -95,6 +105,7 @@ export const useDisplayStore = defineStore('display', {
     displayAnnotationsTree: true,
     displayEntityTypes: true,
     displayElementClasses: false,
+    displayAllPaths: getShowPaths(),
     elementsTableLayout: false,
     compactDisplay: false,
     imageShow: true,
@@ -132,6 +143,14 @@ export const useDisplayStore = defineStore('display', {
       if (typeof value === 'boolean') this.compactDisplay = value
       else this.compactDisplay = !this.compactDisplay
     },
+    toggleAllPaths (value: boolean | null = null) {
+      if (typeof value === 'boolean') this.displayAllPaths = value
+      else this.displayAllPaths = !this.displayAllPaths
+
+      if (typeof window !== 'undefined' && window.sessionStorage) {
+        window.sessionStorage.setItem('showPaths', this.displayAllPaths.toString())
+      }
+    },
     toggleDropdown (id: string, value: boolean | null = null) {
       if (typeof value === 'boolean') {
         this.dropdowns = {
diff --git a/src/views/Element.vue b/src/views/Element.vue
index 82242357afa735aeb19ffee23dd8753fb072a399..b83e700e1b1cc6a3fe2bbdac7e4034328196706c 100644
--- a/src/views/Element.vue
+++ b/src/views/Element.vue
@@ -242,8 +242,7 @@ export default {
       })
     },
     isNeighbor (id) {
-      const neighbors = this.neighbors[this.id]?.results.map(n => n.element.id)
-      return neighbors && neighbors.includes(this.id) && neighbors.includes(id)
+      return this.neighbors[this.id]?.flatMap(({ previous, next }) => [previous?.id, next?.id]).includes(id) ?? false
     }
   },
   watch: {
diff --git a/tests/unit/samples.js b/tests/unit/samples.js
index cc67c266ffde055c7147d3a598f6b55bfda75ec0..0a7e22e2b5ce58ea735b0c60d005bbbeda18868e 100644
--- a/tests/unit/samples.js
+++ b/tests/unit/samples.js
@@ -297,30 +297,20 @@ export const entitiesInTranscriptionSample = {
   ]
 }
 
-export const elementNeighborsSample = makeSampleResults([
+export const elementNeighborsSample = [
   {
-    position: 3,
-    element: {
+    ordering: 3,
+    previous: {
       id: 'elementidx',
       type: 'page',
       name: 'element 3'
     },
-    parents: [
-      {
-        id: 'volumeid',
-        type: 'volume',
-        name: 'this is a volume'
-      }
-    ]
-  },
-  {
-    position: 4,
-    element: {
-      id: 'elementid',
+    next: {
+      id: 'elementidx',
       type: 'page',
       name: 'element 4'
     },
-    parents: [
+    path: [
       {
         id: 'volumeid',
         type: 'volume',
@@ -329,13 +319,18 @@ export const elementNeighborsSample = makeSampleResults([
     ]
   },
   {
-    position: 5,
-    element: {
-      id: 'elementidy',
+    ordering: 8,
+    previous: {
+      id: 'elementidx',
       type: 'page',
-      name: 'element 5'
+      name: 'element 8'
     },
-    parents: [
+    next: {
+      id: 'elementidx',
+      type: 'page',
+      name: 'element 10'
+    },
+    path: [
       {
         id: 'volumeid',
         type: 'volume',
@@ -343,7 +338,7 @@ export const elementNeighborsSample = makeSampleResults([
       }
     ]
   }
-])
+]
 
 export const linksSample = makeSampleResults(
   [{
diff --git a/tests/unit/store/elements.spec.js b/tests/unit/store/elements.spec.js
index dcd5cef8964d3746689ca54bc80fcc2bfd961aee..c6fe63860b6f08b78136bfb85970ebe476c2ae36 100644
--- a/tests/unit/store/elements.spec.js
+++ b/tests/unit/store/elements.spec.js
@@ -220,45 +220,42 @@ describe('elements', () => {
     describe('addNeighbors', () => {
       it('add neighbors to an element', () => {
         const state = { neighbors: {} }
-        const neighbors = {
-          results: [
-            {
-              element: { id: 'elementid' },
-              parents: [
-                { id: 'folderid' }
-              ],
-              position: 42
-            }
-          ]
-        }
+        const neighbors = [
+          {
+            previous: { id: 'elementid' },
+            next: { id: 'elementid' },
+            path: [
+              { id: 'folderid' }
+            ],
+            ordering: 42
+          }
+        ]
         mutations.addNeighbors(state, { element: 'element1', neighbors })
         assert.deepStrictEqual(state, { neighbors: { element1: neighbors } })
       })
 
       it('removes unknown parents', () => {
-        const payload = {
-          results: [
-            {
-              element: { id: 'elementid' },
-              parents: [
-                { id: 'folderid' },
-                null
-              ],
-              position: 42
-            }
-          ]
-        }
-        const expected = {
-          results: [
-            {
-              element: { id: 'elementid' },
-              parents: [
-                { id: 'folderid' }
-              ],
-              position: 42
-            }
-          ]
-        }
+        const payload = [
+          {
+            previous: { id: 'elementid' },
+            next: { id: 'elementid' },
+            path: [
+              { id: 'folderid' },
+              null
+            ],
+            ordering: 42
+          }
+        ]
+        const expected = [
+          {
+            previous: { id: 'elementid' },
+            next: { id: 'elementid' },
+            path: [
+              { id: 'folderid' }
+            ],
+            ordering: 42
+          }
+        ]
         const state = { neighbors: {} }
 
         assert.throws(
diff --git a/tests/unit/stores/display.spec.js b/tests/unit/stores/display.spec.js
index eb1df23ab68a82c3a8fb57ec912306a9da3f9364..baa4a51a7d9563da9b62d694addd4782ee1de7a7 100644
--- a/tests/unit/stores/display.spec.js
+++ b/tests/unit/stores/display.spec.js
@@ -106,7 +106,24 @@ describe('display', () => {
       store.toggleCompactDisplay(true)
       assert.ok(store.compactDisplay)
       store.toggleCompactDisplay(false)
-      assert.ok(!store.compactDisplays)
+      assert.ok(!store.compactDisplay)
+    })
+  })
+
+  describe('toggleAllPaths', () => {
+    it('toggles without a value', () => {
+      assert.ok(!store.displayAllPaths)
+      store.toggleAllPaths()
+      assert.ok(store.displayAllPaths)
+    })
+
+    it('sets directly with a boolean value', () => {
+      store.displayAllPaths = false
+      assert.ok(!store.displayAllPaths)
+      store.toggleAllPaths(true)
+      assert.ok(store.displayAllPaths)
+      store.toggleAllPaths(false)
+      assert.ok(!store.displayAllPaths)
     })
   })