diff --git a/module/finc/src/finc/RecordTab/HierarchyTree.php b/module/finc/src/finc/RecordTab/HierarchyTree.php
index 315b773894fe50aa0da87b36fdf6c63318eb1ae9..56133533858816cab39174a1e310b1cf762716c5 100644
--- a/module/finc/src/finc/RecordTab/HierarchyTree.php
+++ b/module/finc/src/finc/RecordTab/HierarchyTree.php
@@ -67,4 +67,15 @@ class HierarchyTree extends \VuFind\RecordTab\HierarchyTree
         }
         return false;
     }
+
+    /**
+     * Can this tab be loaded via AJAX?
+     *
+     * @return bool
+     */
+    public function supportsAjax()
+    {
+        // No, special width adjustment needed.
+        return true;
+    }
 }
diff --git a/themes/finc-accessibility/js/cart.js b/themes/finc-accessibility/js/cart.js
new file mode 100644
index 0000000000000000000000000000000000000000..9fc90e6810a59fd411c5861d382083f1672054af
--- /dev/null
+++ b/themes/finc-accessibility/js/cart.js
@@ -0,0 +1,287 @@
+/*global Cookies, VuFind */
+/*exported cartFormHandler */
+
+VuFind.register('cart', function Cart() {
+  var _COOKIE = 'vufind_cart';
+  var _COOKIE_SOURCES = 'vufind_cart_src';
+  var _COOKIE_DELIM = "\t";
+  var _COOKIE_DOMAIN = false;
+  var _COOKIE_PATH = '/';
+
+  function setDomain(domain) {
+    _COOKIE_DOMAIN = domain;
+  }
+
+  function setCookiePath(path) {
+    _COOKIE_PATH = path;
+  }
+
+  function _uniqueArray(op) {
+    var ret = [];
+    for (var i = 0; i < op.length; i++) {
+      if (ret.indexOf(op[i]) < 0) {
+        ret.push(op[i]);
+      }
+    }
+    return ret;
+  }
+
+  function _getItems() {
+    var items = Cookies.getItem(_COOKIE);
+    if (items) {
+      return items.split(_COOKIE_DELIM);
+    }
+    return [];
+  }
+  function _getSources() {
+    var items = Cookies.getItem(_COOKIE_SOURCES);
+    if (items) {
+      return items.split(_COOKIE_DELIM);
+    }
+    return [];
+  }
+  function getFullItems() {
+    var items = _getItems();
+    var sources = _getSources();
+    var full = [];
+    if (items.length === 0) {
+      return [];
+    }
+    for (var i = items.length; i--;) {
+      full[full.length] = sources[items[i].charCodeAt(0) - 65] + '|' + items[i].substr(1);
+    }
+    return full;
+  }
+
+  function hasItem(id, _source) {
+    var source = _source || VuFind.defaultSearchBackend;
+    return _getItems().indexOf(String.fromCharCode(65 + _getSources().indexOf(source)) + id) > -1;
+  }
+
+  function _refreshToggles() {
+    var $toggleBtns = $('.btn-bookbag-toggle');
+    if ($toggleBtns.length > 0) {
+      $toggleBtns.each(function cartIdEach() {
+        var $this = $(this);
+        $this.find('.cart-add,.cart-remove').addClass('hidden');
+        if (hasItem($this.data('cart-id'), $this.data('cart-source'))) {
+          $this.find('.cart-remove').removeClass('hidden');
+        } else {
+          $this.find('.cart-add').removeClass('hidden');
+        }
+      });
+    }
+  }
+
+  function updateCount() {
+    var items = VuFind.cart.getFullItems();
+    $('#cartItems strong').html(items.length);
+    if (items.length === parseInt(VuFind.translate('bookbagMax'), 10)) {
+      $('#cartItems .full').removeClass('hidden');
+    } else {
+      $('#cartItems .full').addClass('hidden');
+    }
+    _refreshToggles();
+  }
+
+  function addItem(id, _source) {
+    var source = _source || VuFind.defaultSearchBackend;
+    var cartItems = _getItems();
+    var cartSources = _getSources();
+    if (cartItems.length >= parseInt(VuFind.translate('bookbagMax'), 10)) {
+      return false;
+    }
+    var sIndex = cartSources.indexOf(source);
+    if (sIndex < 0) {
+      // Add source to source cookie
+      cartItems[cartItems.length] = String.fromCharCode(65 + cartSources.length) + id;
+      cartSources[cartSources.length] = source;
+      Cookies.setItem(_COOKIE_SOURCES, cartSources.join(_COOKIE_DELIM), false, _COOKIE_PATH, _COOKIE_DOMAIN);
+    } else {
+      cartItems[cartItems.length] = String.fromCharCode(65 + sIndex) + id;
+    }
+    Cookies.setItem(_COOKIE, _uniqueArray(cartItems).join(_COOKIE_DELIM), false, _COOKIE_PATH, _COOKIE_DOMAIN);
+    updateCount();
+    return true;
+  }
+  function removeItem(id, source) {
+    var cartItems = _getItems();
+    var cartSources = _getSources();
+    // Find
+    var cartIndex = cartItems.indexOf(String.fromCharCode(65 + cartSources.indexOf(source)) + id);
+    if (cartIndex > -1) {
+      var sourceIndex = cartItems[cartIndex].charCodeAt(0) - 65;
+      var saveSource = false;
+      for (var i = cartItems.length; i--;) {
+        if (i === cartIndex) {
+          continue;
+        }
+        // If this source is shared by another, keep it
+        if (cartItems[i].charCodeAt(0) - 65 === sourceIndex) {
+          saveSource = true;
+          break;
+        }
+      }
+      cartItems.splice(cartIndex, 1);
+      // Remove unused sources
+      if (!saveSource) {
+        var oldSources = cartSources.slice(0);
+        cartSources.splice(sourceIndex, 1);
+        // Adjust source index characters
+        for (var j = cartItems.length; j--;) {
+          var si = cartItems[j].charCodeAt(0) - 65;
+          var ni = cartSources.indexOf(oldSources[si]);
+          cartItems[j] = String.fromCharCode(65 + ni) + cartItems[j].substring(1);
+        }
+      }
+      if (cartItems.length > 0) {
+        Cookies.setItem(_COOKIE, _uniqueArray(cartItems).join(_COOKIE_DELIM), false, _COOKIE_PATH, _COOKIE_DOMAIN);
+        Cookies.setItem(_COOKIE_SOURCES, _uniqueArray(cartSources).join(_COOKIE_DELIM), false, _COOKIE_PATH, _COOKIE_DOMAIN);
+      } else {
+        Cookies.removeItem(_COOKIE, _COOKIE_PATH, _COOKIE_DOMAIN);
+        Cookies.removeItem(_COOKIE_SOURCES, _COOKIE_PATH, _COOKIE_DOMAIN);
+      }
+      updateCount();
+      return true;
+    }
+    return false;
+  }
+
+  var _cartNotificationTimeout = false;
+  function _registerUpdate(_form) {
+    var $form = typeof _form === 'undefined'
+      ? $('form[name="bulkActionForm"]')
+      : $(_form);
+    $("#updateCart, #bottom_updateCart").unbind('click').click(function cartUpdate() {
+      var elId = this.id;
+      var selected = [];
+      var addToSelected = function processCartFormValues() {
+        if (-1 === selected.indexOf(this.value)) {
+          selected.push(this.value);
+        }
+      };
+      var selectedInForm = $form.find('input[name="ids[]"]:checked');
+      var selectedFormAttr = $('input[form="' + $form.attr('id') + '"][name="ids[]"]:checked');
+      $(selectedInForm).each(addToSelected);
+      $(selectedFormAttr).each(addToSelected);
+      if (selected.length > 0) {
+        var msg = "";
+        var orig = getFullItems();
+        $(selected).each(function cartCheckedItemsAdd() {
+          var data = this.split('|');
+          addItem(data[1], data[0]);
+        });
+        var updated = getFullItems();
+        var added = updated.length - orig.length;
+        var inCart = selected.length - added;
+        msg += VuFind.translate('itemsAddBag', {'%%count%%': added});
+        if (updated.length >= parseInt(VuFind.translate('bookbagMax'), 10)) {
+          msg += "<br/>" + VuFind.translate('bookbagFull');
+        }
+        if (inCart > 0 && orig.length > 0) {
+          msg += "<br/>" + VuFind.translate('itemsInBag', {'%%count%%': inCart});
+        }
+        $('#' + elId).data('bs.popover').options.content = msg;
+        $('#cartItems strong').html(updated.length);
+      } else {
+        $('#' + elId).data('bs.popover').options.content = VuFind.translate('bulk_noitems_advice');
+      }
+      $('#' + elId).popover('show');
+      if (_cartNotificationTimeout !== false) {
+        clearTimeout(_cartNotificationTimeout);
+      }
+      _cartNotificationTimeout = setTimeout(function notificationHide() {
+        $('#' + elId).popover('hide');
+      }, 5000);
+      return false;
+    });
+  }
+
+  function _registerToggles() {
+    var $toggleBtns = $('.btn-bookbag-toggle');
+    if ($toggleBtns.length > 0) {
+      $toggleBtns.each(function cartIdEach() {
+        var $this = $(this);
+        var currentId = $this.data('cart-id');
+        var currentSource = $this.data('cart-source');
+        $this.find('.correct').removeClass('correct hidden');
+        $this.find('.cart-add').click(function cartAddClick(e) {
+          e.preventDefault();
+          if (addItem(currentId, currentSource)) {
+            $this.find('.cart-add').addClass('hidden');
+            /* #20374 set focus */
+            $this.find('.cart-remove').removeClass('hidden').focus();
+            /* #20374 set focus - END*/
+          } else {
+            $this.popover({content: VuFind.translate('bookbagFull')});
+            setTimeout(function recordCartFullHide() {
+              $this.popover('hide');
+            }, 5000);
+          }
+        });
+        $this.find('.cart-remove').click(function cartRemoveClick(e) {
+          e.preventDefault();
+          removeItem(currentId, currentSource);
+          /* #20374 set focus */
+          $this.find('.cart-add').removeClass('hidden').focus();
+          /* #20374 set focus - END */
+          $this.find('.cart-remove').addClass('hidden');
+        });
+      });
+    }
+  }
+
+  function init() {
+    // Record buttons
+    _registerToggles();
+    // Search results
+    _registerUpdate();
+    $("#updateCart, #bottom_updateCart").popover({
+      content: '',
+      html: true,
+      trigger: 'manual',
+      placement: $(document.body).hasClass('rtl') ? 'left' : 'right'
+    });
+    /* #18034 accessibility: inform screen reader about changes, eventually intregrate by PR into bootstrap - RL */
+    var cart = document.getElementById("cartSummary");
+    if (cart !== null && cart !== undefined) {
+      cart.setAttribute("aria-live", "polite");
+      cart.setAttribute("aria-atomic", "true");
+    }
+    /* #18034 - END */
+    updateCount();
+  }
+
+  // Reveal
+  return {
+    // Methods
+    addItem: addItem,
+    getFullItems: getFullItems,
+    hasItem: hasItem,
+    removeItem: removeItem,
+    setCookiePath: setCookiePath,
+    setDomain: setDomain,
+    updateCount: updateCount,
+    // Init
+    init: init
+  };
+});
+
+// Building an array and checking indexes prevents a race situation
+// We want to prioritize empty over printing
+function cartFormHandler(event, data) {
+  var keys = [];
+  for (var i in data) {
+    if (Object.prototype.hasOwnProperty.call(data, i)) {
+      keys.push(data[i].name);
+    }
+  }
+  if (keys.indexOf('ids[]') === -1) {
+    return null;
+  }
+  if (keys.indexOf('print') > -1) {
+    return true;
+  }
+}
+
+document.addEventListener('VuFind.lightbox.closed', VuFind.cart.updateCount, false);
diff --git a/themes/finc-accessibility/js/record.js b/themes/finc-accessibility/js/record.js
index 9766867212c7524e3ed39a0a6eac7c250fc27d76..26da27f6f5f484bf429a4eab12162fc12bf15de8 100644
--- a/themes/finc-accessibility/js/record.js
+++ b/themes/finc-accessibility/js/record.js
@@ -274,6 +274,8 @@ function recordDocReady() {
 
     // accessibility: mark tab controls as selected
     $top.find('.record-tab.active').find('a').attr('aria-selected', 'false');
+    // accessibility: set information about connection between tab control and tab content
+    $(this).attr('aria-controls', tabid);
     $('#' + tabid + '-tabselector').attr('aria-selected', 'true').attr('aria-controls', tabid);
 
     // accessibility: set aria-hidden for content panes
diff --git a/themes/finc-accessibility/js/vendor/bootstrap-accessibility-de.min.js b/themes/finc-accessibility/js/vendor/bootstrap-accessibility-de.min.js
index 0b23dca9f44e502f5c348a865c348630a554e075..9462f550c7f0d71ac6de52ed7987fe5831e5d3fe 100644
--- a/themes/finc-accessibility/js/vendor/bootstrap-accessibility-de.min.js
+++ b/themes/finc-accessibility/js/vendor/bootstrap-accessibility-de.min.js
@@ -327,4 +327,9 @@ $(document).on('keyup', '.dropdown-abort', function(e) {
             toggle.dropdown("toggle");
         }
     }
+});
+
+/* restore focus after closing of lightbox */
+$(document).on('click', '.bulkActionButtons input', function(e) {
+    VuFind.lightbox.setOrigin(e.target);
 });
\ No newline at end of file
diff --git a/themes/finc-accessibility/js/vendor/bootstrap-accessibility-en.min.js b/themes/finc-accessibility/js/vendor/bootstrap-accessibility-en.min.js
index 11bef8e1ba5fde3b9db5fe1c6b18a7239e3b23a1..7717b77ecd987717df53a4ae4de3c44e81629e1d 100644
--- a/themes/finc-accessibility/js/vendor/bootstrap-accessibility-en.min.js
+++ b/themes/finc-accessibility/js/vendor/bootstrap-accessibility-en.min.js
@@ -327,4 +327,9 @@ $(document).on('keyup', '.dropdown-abort', function(e) {
             toggle.dropdown("toggle");
         }
     }
+});
+
+/* restore focus after closing of lightbox */
+$(document).on('click', '.bulkActionButtons input', function(e) {
+    VuFind.lightbox.setOrigin(e.target);
 });
\ No newline at end of file
diff --git a/themes/finc/js/cart-finc.js b/themes/finc/js/cart-finc.js
deleted file mode 100644
index 0fbaf1015f44cd429d87a2f1db9a0f5745c5c320..0000000000000000000000000000000000000000
--- a/themes/finc/js/cart-finc.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/* #18034 - inform screen reader about changes, eventually intregrate by PR into bootstrap cart.js - RL */
-$(document).ready(function() {
-  var cart = document.getElementById("cartSummary");
-  if (cart != null) {
-    cart.setAttribute("aria-live", "polite");
-    cart.setAttribute("aria-atomic", "true");
-  }
-});
diff --git a/themes/finc/templates/ajax/resolverLinks.phtml b/themes/finc/templates/ajax/resolverLinks.phtml
index cdc5ac85facdc8c80928de7ad8b60646db73edb8..4b2e0a9ed2b4ee8050d643752941eb0adb76f175 100644
--- a/themes/finc/templates/ajax/resolverLinks.phtml
+++ b/themes/finc/templates/ajax/resolverLinks.phtml
@@ -20,7 +20,14 @@
                 <span class="last"></span>
               </div>
               <?php /* finc-specific change #7986 - END */ ?>
-              <a href="<?=$this->escapeHtmlAttr($link['href'])?>" title="<?=isset($link['service_type'])?$this->escapeHtmlAttr($link['service_type']):''?>"<?=!empty($link['access'])?' class="access-'.$link['access'].'"':''?>><?=isset($link['title'])?$this->escapeHtml($link['title']):''?></a> <br />
+              <?= $this->externalLink(
+                    $this->escapeHtmlAttr($link['href']),
+                    $link['title'] ?? '',
+                    [
+                        'title' => $link['service_type'] ?? '',
+                        'class' => !empty($link['access']) ? 'access-' . $link['access'] : ''
+                    ]
+                  ) ?> <br />
               <?php /* finc-specific change #5334 - CK */ ?>
               <small>
                 <?= isset($link['coverage']) ? $this->escapeHtml($link['coverage']) : '' ?>
diff --git a/themes/finc/templates/record/view.phtml b/themes/finc/templates/record/view.phtml
index 3749c2121c6fc81e1f807f1b38c5e40014cb3a48..076ef6fb512970578a5aac9a2f531bdacdc6a6c8 100644
--- a/themes/finc/templates/record/view.phtml
+++ b/themes/finc/templates/record/view.phtml
@@ -71,7 +71,7 @@
                   <a href="<?= $this->recordLink()->getTabUrl($this->driver, $tab) ?>#tabnav"
                     <?php if ($obj->supportsAjax() && in_array($tab, $this->backgroundTabs)): ?> data-background<?php endif ?>
                      aria-selected="<?= $isActiveTab ? "true" : "false" ?>"
-                     aria-controls="<?= $tabName ?>"
+                     <?php if($isActiveTab): ?>aria-controls="<?= $tabName ?>"<?php endif; ?>
                      id="<?= $tabName ?>-tabselector">
                     <?= $this->transEsc($desc) ?>
                     <span class="sr-only load-tab-content"><?= $this->transEsc('load_tab_content_hint') ?></span></a>
diff --git a/themes/finc/theme.config.php b/themes/finc/theme.config.php
index c20700c8971b8c09e40fc3d0cd8e4d267cf4477d..652545a3d02d4d550bb1be2fc57cace7edd3cac8 100644
--- a/themes/finc/theme.config.php
+++ b/themes/finc/theme.config.php
@@ -5,8 +5,7 @@ return [
         'check_item_statuses.js',
         'lightbox_form_cache.js',
         'covers.js',
-        'common-finc.js',
-        'cart-finc.js'
+        'common-finc.js'
     ],
     'helpers' => [
         'aliases' => [