diff --git a/core/modules/navigation/css/components/admin-toolbar.css b/core/modules/navigation/css/components/admin-toolbar.css
index f5f0536a10295edd9ed723ddddaf2058800e8d7f..6ea6c5d05bddddf05d7a72cc9341128843f32258 100644
--- a/core/modules/navigation/css/components/admin-toolbar.css
+++ b/core/modules/navigation/css/components/admin-toolbar.css
@@ -63,7 +63,7 @@ body {
   z-index: var(--admin-toolbar-z-index);
   display: flex;
   flex-direction: column;
-  height: 100vh;
+  block-size: 100vh;
   transform: translateX(-100%);
   background-color: var(--admin-toolbar-color-white);
   font-family: var(--admin-toolbar-font-family);
@@ -92,7 +92,9 @@ body {
 }
 @media (min-width: 64rem) {
   .admin-toolbar {
+    block-size: calc(100vh - var(--drupal-displace-offset-top, 0px));
     transform: none;
+    inset-block-start: var(--drupal-displace-offset-top, 0);
   }
 }
 @media only screen and (max-height: 18.75rem) {
diff --git a/core/modules/navigation/css/components/admin-toolbar.pcss.css b/core/modules/navigation/css/components/admin-toolbar.pcss.css
index 9d9a447b2908ae799ee54a8fed8d3c180475783f..5b1516b9bf2bfdc963c8f05702e22ee51384e05b 100644
--- a/core/modules/navigation/css/components/admin-toolbar.pcss.css
+++ b/core/modules/navigation/css/components/admin-toolbar.pcss.css
@@ -63,7 +63,7 @@ body {
   z-index: var(--admin-toolbar-z-index);
   display: flex;
   flex-direction: column;
-  height: 100vh;
+  block-size: 100vh;
   transform: translateX(-100%);
   background-color: var(--admin-toolbar-color-white);
   font-family: var(--admin-toolbar-font-family);
@@ -93,7 +93,9 @@ body {
   }
 
   @media (--admin-toolbar-desktop) {
+    block-size: calc(100vh - var(--drupal-displace-offset-top, 0px));
     transform: none;
+    inset-block-start: var(--drupal-displace-offset-top, 0);
   }
 
   @media only screen and (max-height: 300px) {
diff --git a/core/modules/navigation/css/components/toolbar-popover.css b/core/modules/navigation/css/components/toolbar-popover.css
index c1e795b1cac9b3ba37bdce164e904b491a42e053..76f587a325e60de593652e338b7d4e5a08f60462 100644
--- a/core/modules/navigation/css/components/toolbar-popover.css
+++ b/core/modules/navigation/css/components/toolbar-popover.css
@@ -44,6 +44,7 @@
   [data-toolbar-popover-wrapper] {
     --admin-toolbar-z-index-popover: var(--drupal-admin-z-index-popover, -1);
 
+    block-size: calc(100vh - var(--drupal-displace-offset-top, 0px));
     padding-block-start: var(--admin-toolbar-space-16);
     transform: translateX(0);
     box-shadow:
@@ -51,7 +52,7 @@
       0 0 8px rgba(0, 0, 0, 0.04),
       0 0 40px rgba(0, 0, 0, 0.06);
     inline-size: var(--admin-toolbar-popover-width);
-    inset-block-start: 0;
+    inset-block-start: var(--drupal-displace-offset-top, 0);
     inset-inline-start: 1px;
   }
 }
diff --git a/core/modules/navigation/css/components/toolbar-popover.pcss.css b/core/modules/navigation/css/components/toolbar-popover.pcss.css
index ffdc04fa4e5fa4a48c5f8612ae003ce8f34fd3c4..6a8b2a019c24bdafc1b695c4429e223b822628d7 100644
--- a/core/modules/navigation/css/components/toolbar-popover.pcss.css
+++ b/core/modules/navigation/css/components/toolbar-popover.pcss.css
@@ -43,6 +43,7 @@
   @media (--admin-toolbar-desktop) {
     --admin-toolbar-z-index-popover: var(--drupal-admin-z-index-popover, -1);
 
+    block-size: calc(100vh - var(--drupal-displace-offset-top, 0px));
     padding-block-start: var(--admin-toolbar-space-16);
     transform: translateX(0);
     box-shadow:
@@ -50,7 +51,7 @@
       0 0 8px rgba(0, 0, 0, 0.04),
       0 0 40px rgba(0, 0, 0, 0.06);
     inline-size: var(--admin-toolbar-popover-width);
-    inset-block-start: 0;
+    inset-block-start: var(--drupal-displace-offset-top, 0);
     inset-inline-start: 1px;
   }
 }
diff --git a/core/modules/navigation/css/components/tooltip.css b/core/modules/navigation/css/components/tooltip.css
index 1571d00035da21f192778b8f4c74fa0b9696da3c..25a20bb34130ddf0c46081d0ea5c4d9387cff0dd 100644
--- a/core/modules/navigation/css/components/tooltip.css
+++ b/core/modules/navigation/css/components/tooltip.css
@@ -22,9 +22,11 @@
   font-variation-settings: "wght" 600;
   line-height: var(--admin-toolbar-line-height-info-sm);
 }
-[data-drupal-tooltip]:hover + .toolbar-tooltip,
-[data-drupal-tooltip]:focus + .toolbar-tooltip {
-  display: block;
+@media (min-width: 64rem) {
+  [data-drupal-tooltip]:hover + .toolbar-tooltip,
+  [data-drupal-tooltip]:focus + .toolbar-tooltip {
+    display: block;
+  }
 }
 [data-admin-toolbar="expanded"] [data-drupal-tooltip]:hover + .toolbar-block__title-tooltip {
   display: none;
diff --git a/core/modules/navigation/css/components/tooltip.pcss.css b/core/modules/navigation/css/components/tooltip.pcss.css
index 7af2010c2f4f7fd48650a760644ab566a5487b5d..35462424121c5ec5b5b65013e2fbde259275a45b 100644
--- a/core/modules/navigation/css/components/tooltip.pcss.css
+++ b/core/modules/navigation/css/components/tooltip.pcss.css
@@ -4,6 +4,8 @@
  * Tooltip styles.
  */
 
+@import "../base/media-queries.pcss.css";
+
 .toolbar-tooltip {
   position: fixed;
   z-index: var(--admin-toolbar-z-index-tooltip);
@@ -18,9 +20,11 @@
   line-height: var(--admin-toolbar-line-height-info-sm);
 }
 
-[data-drupal-tooltip]:hover + .toolbar-tooltip,
-[data-drupal-tooltip]:focus + .toolbar-tooltip {
-  display: block;
+@media (--admin-toolbar-desktop) {
+  [data-drupal-tooltip]:hover + .toolbar-tooltip,
+  [data-drupal-tooltip]:focus + .toolbar-tooltip {
+    display: block;
+  }
 }
 
 [data-admin-toolbar="expanded"] [data-drupal-tooltip]:hover + .toolbar-block__title-tooltip {
diff --git a/core/modules/navigation/css/components/top-bar.css b/core/modules/navigation/css/components/top-bar.css
index c2d15b21fb2ff0533c54b6251e7c4cec3277d3df..9e0eb2f928bfa50a9fcb555ded2573dc0a3138f4 100644
--- a/core/modules/navigation/css/components/top-bar.css
+++ b/core/modules/navigation/css/components/top-bar.css
@@ -11,17 +11,18 @@
   position: relative;
   z-index: var(--admin-toolbar-z-index-top-bar);
   display: flex;
-  padding-inline: var(--admin-toolbar-space-4);
-  padding-block: var(--admin-toolbar-space-4);
+  display: none;
   background-color: white;
   box-shadow: 0 0 8px 0 var(--admin-toolbar-color-shadow-15);
   font-family: var(--admin-toolbar-font-family);
+  padding-inline: var(--admin-toolbar-space-4);
+  padding-block: var(--admin-toolbar-space-4);
 }
 @media (min-width: 64rem) {
   .top-bar {
     block-size: var(--admin-toolbar-top-bar-height);
     position: fixed;
-    inset-block-start: 0;
+    inset-block-start: var(--drupal-displace-offset-top, 0);
     inset-inline-start: 0;
     width: 100vw;
     padding-block: var(--admin-toolbar-space-12);
@@ -35,23 +36,22 @@
     padding-inline: calc(var(--drupal-displace-offset-right, var(--admin-toolbar-sidebar-width)) + var(--admin-toolbar-space-32)) var(--admin-toolbar-space-32);
   }
 }
-/* When only one burger button hide top bar on desktop. */
-@media (min-width: 64rem) {
-  .top-bar:has(.top-bar__burger:only-child) {
-    display: none;
-  }
+.top-bar:has(.top-bar__tools:not(:empty), .top-bar__context:not(:empty), .top-bar__actions:not(:empty)) {
+  display: block;
 }
 @media (min-width: 64rem) {
-  .top-bar:not(:has(.top-bar__burger:only-child)) ~ .dialog-off-canvas-main-canvas {
+  .top-bar:has(.top-bar__tools:not(:empty), .top-bar__context:not(:empty), .top-bar__actions:not(:empty)) ~ .dialog-off-canvas-main-canvas {
     margin-block-start: var(--admin-toolbar-top-bar-height);
   }
 }
-.top-bar__burger {
-  align-self: start;
+.top-bar__actions {
+  display: flex;
+  gap: 0.5rem;
 }
 @media (min-width: 64rem) {
-  .top-bar__burger {
-    display: none;
+  .top-bar__actions {
+    justify-content: end;
+    gap: var(--admin-toolbar-space-4);
   }
 }
 .top-bar__content {
@@ -71,3 +71,13 @@
     gap: var(--admin-toolbar-space-8);
   }
 }
+.top-bar__context {
+  display: flex;
+  gap: 0.5rem;
+  align-items: center;
+  justify-content: start;
+}
+.top-bar__tools {
+  display: flex;
+  gap: 0.5rem;
+}
diff --git a/core/modules/navigation/css/components/top-bar.pcss.css b/core/modules/navigation/css/components/top-bar.pcss.css
index 7fb795c1db4c46b8d5003e2b514176486a47b42a..3a1c5cfb254e03dfb46f65fbe36712a7dc366b3e 100644
--- a/core/modules/navigation/css/components/top-bar.pcss.css
+++ b/core/modules/navigation/css/components/top-bar.pcss.css
@@ -8,16 +8,17 @@
   position: relative;
   z-index: var(--admin-toolbar-z-index-top-bar);
   display: flex;
-  padding-inline: var(--admin-toolbar-space-4);
-  padding-block: var(--admin-toolbar-space-4);
+  display: none;
   background-color: white;
   box-shadow: 0 0 8px 0 var(--admin-toolbar-color-shadow-15);
   font-family: var(--admin-toolbar-font-family);
+  padding-inline: var(--admin-toolbar-space-4);
+  padding-block: var(--admin-toolbar-space-4);
 
   @media (--admin-toolbar-desktop) {
     block-size: var(--admin-toolbar-top-bar-height);
     position: fixed;
-    inset-block-start: 0;
+    inset-block-start: var(--drupal-displace-offset-top, 0);
     inset-inline-start: 0;
     width: 100vw;
     padding-block: var(--admin-toolbar-space-12);
@@ -32,23 +33,23 @@
   }
 }
 
-/* When only one burger button hide top bar on desktop. */
-.top-bar:has(.top-bar__burger:only-child) {
-  @media (--admin-toolbar-desktop) {
-    display: none;
-  }
-}
+.top-bar:has(.top-bar__tools:not(:empty), .top-bar__context:not(:empty), .top-bar__actions:not(:empty)) {
+  display: block;
 
-.top-bar:not(:has(.top-bar__burger:only-child)) ~ .dialog-off-canvas-main-canvas {
-  @media (--admin-toolbar-desktop) {
-    margin-block-start: var(--admin-toolbar-top-bar-height);
+  ~ .dialog-off-canvas-main-canvas {
+    @media (--admin-toolbar-desktop) {
+      margin-block-start: var(--admin-toolbar-top-bar-height);
+    }
   }
 }
 
-.top-bar__burger {
-  align-self: start;
+.top-bar__actions {
+  display: flex;
+  gap: 0.5rem;
+
   @media (--admin-toolbar-desktop) {
-    display: none;
+    justify-content: end;
+    gap: var(--admin-toolbar-space-4);
   }
 }
 
@@ -69,3 +70,15 @@
     gap: var(--admin-toolbar-space-8);
   }
 }
+
+.top-bar__context {
+  display: flex;
+  gap: 0.5rem;
+  align-items: center;
+  justify-content: start;
+}
+
+.top-bar__tools {
+  display: flex;
+  gap: 0.5rem;
+}
diff --git a/core/modules/navigation/layouts/navigation.html.twig b/core/modules/navigation/layouts/navigation.html.twig
index afe5152a713a717f247b1e9041a95746e9a4ca7e..3748c239ea79300d295edd624c83c1bbb9b76884 100644
--- a/core/modules/navigation/layouts/navigation.html.twig
+++ b/core/modules/navigation/layouts/navigation.html.twig
@@ -18,7 +18,7 @@
 #}
 {% set control_bar_attributes = create_attribute() %}
 
-<div {{ control_bar_attributes.addClass('admin-toolbar-control-bar').setAttribute('data-drupal-admin-styles', '').setAttribute('data-offset-top', '') }}>
+<div {{ control_bar_attributes.addClass('admin-toolbar-control-bar').setAttribute('data-drupal-admin-styles', '') }}>
   <div class="admin-toolbar-control-bar__content">
     {% include 'navigation:toolbar-button' with {
       attributes: create_attribute({'aria-expanded': 'false', 'aria-controls': 'admin-toolbar', 'type': 'button'}),
diff --git a/core/modules/navigation/navigation.module b/core/modules/navigation/navigation.module
index 74a136250832983e1ac97319154b9efb9179a7fd..8dcdee642ef71df01f79097d06f66160f152e0f1 100644
--- a/core/modules/navigation/navigation.module
+++ b/core/modules/navigation/navigation.module
@@ -4,6 +4,8 @@
  * @file
  */
 
+use Drupal\navigation\TopBarRegion;
+
 /**
  * Implements hook_module_implements_alter().
  */
@@ -18,3 +20,21 @@ function navigation_module_implements_alter(&$implementations, $hook) {
     unset($implementations['layout_builder']);
   }
 }
+
+/**
+ * Prepares variables for navigation top bar template.
+ *
+ * Default template: top-bar.html.twig
+ *
+ * @param $variables
+ *   An associative array containing:
+ *    - element: An associative array containing the properties and children of
+ *      the top bar.
+ */
+function template_preprocess_top_bar(&$variables): void {
+  $element = $variables['element'];
+
+  foreach (TopBarRegion::cases() as $region) {
+    $variables[$region->value] = $element[$region->value] ?? NULL;
+  }
+}
diff --git a/core/modules/navigation/navigation.services.yml b/core/modules/navigation/navigation.services.yml
index 5413372b557b0ea7e99750a4e7debc9595b6cd73..6a8c54d25197e7698305e4a717e75bbd3a0f0919 100644
--- a/core/modules/navigation/navigation.services.yml
+++ b/core/modules/navigation/navigation.services.yml
@@ -14,7 +14,8 @@ services:
         '@file_url_generator',
         '@plugin.manager.layout_builder.section_storage',
         '@request_stack',
-        '@extension.list.module'
+        '@extension.list.module',
+        '@current_user',
       ]
   Drupal\navigation\NavigationRenderer: '@navigation.renderer'
 
@@ -33,3 +34,8 @@ services:
     class: Drupal\navigation\UserLazyBuilder
     arguments: ['@current_user']
   Drupal\navigation\UserLazyBuilders: '@navigation.user_lazy_builder'
+
+  plugin.manager.top_bar_item:
+    class: Drupal\navigation\TopBarItemManager
+    parent: default_plugin_manager
+  Drupal\navigation\TopBarItemManagerInterface: '@plugin.manager.top_bar_item'
diff --git a/core/modules/navigation/src/Attribute/TopBarItem.php b/core/modules/navigation/src/Attribute/TopBarItem.php
new file mode 100644
index 0000000000000000000000000000000000000000..3041d720b1030dda978be8a35b2434d5772d99be
--- /dev/null
+++ b/core/modules/navigation/src/Attribute/TopBarItem.php
@@ -0,0 +1,36 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\navigation\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\navigation\TopBarRegion;
+
+/**
+ * The top bar item attribute.
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+final class TopBarItem extends Plugin {
+
+  /**
+   * Constructs a new TopBarItem instance.
+   *
+   * @param string $id
+   *   The top bar item ID.
+   * @param \Drupal\navigation\TopBarRegion $region
+   *   The region where the top bar item belongs to.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $label
+   *   (optional) The human-readable name of the top bar item.
+   * @param class-string|null $deriver
+   *   (optional) The deriver class.
+   */
+  public function __construct(
+    public readonly string $id,
+    public readonly TopBarRegion $region,
+    public readonly ?TranslatableMarkup $label = NULL,
+    public readonly ?string $deriver = NULL,
+  ) {}
+
+}
diff --git a/core/modules/navigation/src/Element/TopBar.php b/core/modules/navigation/src/Element/TopBar.php
new file mode 100644
index 0000000000000000000000000000000000000000..c664f929c2242e142f014312c55817b29421b9c5
--- /dev/null
+++ b/core/modules/navigation/src/Element/TopBar.php
@@ -0,0 +1,72 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\navigation\Element;
+
+use Drupal\Core\Render\Attribute\RenderElement;
+use Drupal\Core\Render\Element\RenderElementBase;
+use Drupal\navigation\TopBarItemManagerInterface;
+use Drupal\navigation\TopBarRegion;
+
+/**
+ * Provides a render element for the default Drupal toolbar.
+ */
+#[RenderElement('top_bar')]
+class TopBar extends RenderElementBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getInfo(): array {
+    $class = static::class;
+    return [
+      '#pre_render' => [
+        [$class, 'preRenderTopBar'],
+      ],
+      '#theme' => 'top_bar',
+      '#attached' => [
+        'library' => [
+          'navigation/internal.navigation',
+        ],
+      ],
+    ];
+  }
+
+  /**
+   * Builds the TopBar as a structured array ready for rendering.
+   *
+   * Since building the TopBar takes some time, it is done just prior to
+   * rendering to ensure that it is built only if it will be displayed.
+   *
+   * @param array $element
+   *   A renderable array.
+   *
+   * @return array
+   *   A renderable array.
+   *
+   * @see navigation_page_top()
+   */
+  public static function preRenderTopBar($element): array {
+    $top_bar_item_manager = static::topBarItemManager();
+
+    // Group the items by region.
+    foreach (TopBarRegion::cases() as $region) {
+      $items = $top_bar_item_manager->getRenderedTopBarItemsByRegion($region);
+      $element = array_merge($element, [$region->value => $items]);
+    }
+
+    return $element;
+  }
+
+  /**
+   * Wraps the top bar item manager.
+   *
+   * @return \Drupal\navigation\TopBarItemManager
+   *   The top bar item manager.
+   */
+  protected static function topBarItemManager(): TopBarItemManagerInterface {
+    return \Drupal::service(TopBarItemManagerInterface::class);
+  }
+
+}
diff --git a/core/modules/navigation/src/Hook/NavigationHooks.php b/core/modules/navigation/src/Hook/NavigationHooks.php
index 71b9a40791a036f0bb9c7594148cb50cdd280f74..a52f4fab4a1fda44cd60d8153b85cf8ddaa52cc1 100644
--- a/core/modules/navigation/src/Hook/NavigationHooks.php
+++ b/core/modules/navigation/src/Hook/NavigationHooks.php
@@ -76,7 +76,7 @@ public function pageTop(array &$page_top) {
    */
   #[Hook('theme')]
   public function theme($existing, $type, $theme, $path) : array {
-    $items['top_bar'] = ['variables' => ['local_tasks' => []]];
+    $items['top_bar'] = ['render element' => 'element'];
     $items['top_bar_local_tasks'] = ['variables' => ['local_tasks' => []]];
     $items['top_bar_local_task'] = ['variables' => ['link' => []]];
     $items['big_pipe_interface_preview__navigation_shortcut_lazy_builder_lazyLinks__Shortcuts'] = [
diff --git a/core/modules/navigation/src/NavigationRenderer.php b/core/modules/navigation/src/NavigationRenderer.php
index 4aa5bece02dec85f835464dd8cd7e0396cade1cc..1083109f62a9ead9a9b66d0976d4519eaf7ac1c0 100644
--- a/core/modules/navigation/src/NavigationRenderer.php
+++ b/core/modules/navigation/src/NavigationRenderer.php
@@ -18,6 +18,7 @@
 use Drupal\Core\Plugin\Context\Context;
 use Drupal\Core\Plugin\Context\ContextDefinition;
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Session\AccountInterface;
 use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
 
@@ -71,6 +72,7 @@ public function __construct(
     private SectionStorageManagerInterface $sectionStorageManager,
     private RequestStack $requestStack,
     private ModuleExtensionList $moduleExtensionList,
+    private AccountInterface $currentUser,
   ) {}
 
   /**
@@ -170,32 +172,13 @@ public function buildTopBar(array &$page_top): void {
     }
 
     $page_top['top_bar'] = [
-      '#theme' => 'top_bar',
-      '#attached' => [
-        'library' => [
-          'navigation/internal.navigation',
-        ],
-      ],
+      '#type' => 'top_bar',
+      '#access' => $this->currentUser->hasPermission('access navigation'),
       '#cache' => [
-        'contexts' => [
-          'url.path',
-          'user.permissions',
-        ],
+        'keys' => ['top_bar'],
+        'contexts' => ['user.permissions'],
       ],
     ];
-
-    // Local tasks for content entities.
-    if ($this->hasLocalTasks()) {
-      $local_tasks = $this->getLocalTasks();
-      $page_top['top_bar']['#local_tasks'] = [
-        '#theme' => 'top_bar_local_tasks',
-        '#local_tasks' => $local_tasks['tasks'],
-      ];
-      assert($local_tasks['cacheability'] instanceof CacheableMetadata);
-      CacheableMetadata::createFromRenderArray($page_top['top_bar'])
-        ->addCacheableDependency($local_tasks['cacheability'])
-        ->applyTo($page_top['top_bar']);
-    }
   }
 
   /**
@@ -227,7 +210,7 @@ public function removeLocalTasks(array &$build, BlockPluginInterface $block): vo
    * @return array
    *   Local tasks keyed by route name.
    */
-  private function getLocalTasks(): array {
+  public function getLocalTasks(): array {
     if (isset($this->localTasks)) {
       return $this->localTasks;
     }
@@ -279,7 +262,7 @@ private function getLocalTasks(): array {
    * @return bool
    *   TRUE if there are local tasks available for the top bar, FALSE otherwise.
    */
-  private function hasLocalTasks(): bool {
+  public function hasLocalTasks(): bool {
     $local_tasks = $this->getLocalTasks();
     return !empty($local_tasks['tasks']);
   }
diff --git a/core/modules/navigation/src/Plugin/TopBarItem/PageActions.php b/core/modules/navigation/src/Plugin/TopBarItem/PageActions.php
new file mode 100644
index 0000000000000000000000000000000000000000..b432e6189af276fef754744070fa44d4b933abd1
--- /dev/null
+++ b/core/modules/navigation/src/Plugin/TopBarItem/PageActions.php
@@ -0,0 +1,58 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\navigation\Plugin\TopBarItem;
+
+use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\navigation\Attribute\TopBarItem;
+use Drupal\navigation\NavigationRenderer;
+use Drupal\navigation\TopBarItemBase;
+use Drupal\navigation\TopBarRegion;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides the Page Actions basic top bar item.
+ */
+#[TopBarItem(
+  id: 'page_actions',
+  region: TopBarRegion::Actions,
+  label: new TranslatableMarkup('Page Actions'),
+)]
+final class PageActions extends TopBarItemBase implements ContainerFactoryPluginInterface {
+
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, private NavigationRenderer $navigationRenderer) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+  }
+
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get(NavigationRenderer::class)
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build(): array {
+    $build = [];
+    // Local tasks for content entities.
+    if ($this->navigationRenderer->hasLocalTasks()) {
+      $local_tasks = $this->navigationRenderer->getLocalTasks();
+      $build = [
+        '#theme' => 'top_bar_local_tasks',
+        '#local_tasks' => $local_tasks['tasks'],
+      ];
+      assert($local_tasks['cacheability'] instanceof CacheableMetadata);
+      $local_tasks['cacheability']->applyTo($build);
+    }
+
+    return $build;
+  }
+
+}
diff --git a/core/modules/navigation/src/TopBarItemBase.php b/core/modules/navigation/src/TopBarItemBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..7e1dbd2cdfae723ffe2fc03ea60c181b7a5ac4b0
--- /dev/null
+++ b/core/modules/navigation/src/TopBarItemBase.php
@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\navigation;
+
+use Drupal\Component\Plugin\PluginBase;
+
+/**
+ * Base class for top bar item plugins.
+ */
+abstract class TopBarItemBase extends PluginBase implements TopBarItemPluginInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function label(): string|\Stringable {
+    return $this->pluginDefinition['label'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function region(): TopBarRegion {
+    return $this->pluginDefinition['region'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  abstract public function build(): array;
+
+}
diff --git a/core/modules/navigation/src/TopBarItemManager.php b/core/modules/navigation/src/TopBarItemManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..f09490c21f1173c6062904e5eb1b1a169f790d66
--- /dev/null
+++ b/core/modules/navigation/src/TopBarItemManager.php
@@ -0,0 +1,45 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\navigation;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\navigation\Attribute\TopBarItem;
+
+/**
+ * Top bar item plugin manager.
+ */
+final class TopBarItemManager extends DefaultPluginManager implements TopBarItemManagerInterface {
+
+  /**
+   * Constructs the object.
+   */
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Plugin/TopBarItem', $namespaces, $module_handler, TopBarItemPluginInterface::class, TopBarItem::class);
+    $this->alterInfo('top_bar_item');
+    $this->setCacheBackend($cache_backend, 'top_bar_item_plugins');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefinitionsByRegion(TopBarRegion $region): array {
+    return array_filter($this->getDefinitions(), fn (array $definition) => $definition['region'] === $region);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRenderedTopBarItemsByRegion(TopBarRegion $region): array {
+    $instances = [];
+    foreach ($this->getDefinitionsByRegion($region) as $plugin_id => $plugin_definition) {
+      $instances[$plugin_id] = $this->createInstance($plugin_id)->build();
+    }
+
+    return $instances;
+  }
+
+}
diff --git a/core/modules/navigation/src/TopBarItemManagerInterface.php b/core/modules/navigation/src/TopBarItemManagerInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..088715ae33a77bf8e34dc31039aac9419b9db42a
--- /dev/null
+++ b/core/modules/navigation/src/TopBarItemManagerInterface.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\navigation;
+
+/**
+ * Top bar item plugin manager.
+ */
+interface TopBarItemManagerInterface {
+
+  /**
+   * Gets the top bar item plugins by region.
+   *
+   * @param \Drupal\navigation\TopBarRegion $region
+   *   The region.
+   *
+   * @return array
+   *   A list of top bar item plugin definitions.
+   */
+  public function getDefinitionsByRegion(TopBarRegion $region): array;
+
+  /**
+   * Gets the top bar items prepared as render array.
+   *
+   * @param \Drupal\navigation\TopBarRegion $region
+   *   The region.
+   *
+   * @return array
+   *   An array of rendered top bar items, keyed by the plugin ID and sorted by
+   *   weight.
+   */
+  public function getRenderedTopBarItemsByRegion(TopBarRegion $region): array;
+
+}
diff --git a/core/modules/navigation/src/TopBarItemPluginInterface.php b/core/modules/navigation/src/TopBarItemPluginInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..fc73a0dc767eb5ba236b2abf313c1d3a03f7f23d
--- /dev/null
+++ b/core/modules/navigation/src/TopBarItemPluginInterface.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\navigation;
+
+/**
+ * Interface for top bar plugins.
+ */
+interface TopBarItemPluginInterface {
+
+  /**
+   * Returns the translated plugin label.
+   *
+   * @return string|\Stringable
+   *   The translated plugin label.
+   */
+  public function label(): string|\Stringable;
+
+  /**
+   * Returns the plugin region.
+   *
+   * @return \Drupal\navigation\TopBarRegion
+   *   The plugin region.
+   */
+  public function region(): TopBarRegion;
+
+  /**
+   * Builds and returns the renderable array for this top bar item plugin.
+   *
+   * If a top bar item should not be rendered because it has no content, then
+   * this method must also ensure to return no content: it must then only return
+   * an empty array, or an empty array with #cache set (with cacheability
+   * metadata indicating the circumstances for it being empty).
+   *
+   * @return array
+   *   A renderable array representing the content of the top bar item.
+   */
+  public function build();
+
+}
diff --git a/core/modules/navigation/src/TopBarRegion.php b/core/modules/navigation/src/TopBarRegion.php
new file mode 100644
index 0000000000000000000000000000000000000000..bb1de467f65de6539563807747cac1932e68dffa
--- /dev/null
+++ b/core/modules/navigation/src/TopBarRegion.php
@@ -0,0 +1,14 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\navigation;
+
+/**
+ * Enumeration of the Top Bar regions.
+ */
+enum TopBarRegion: string {
+  case Tools = 'tools';
+  case Context = 'context';
+  case Actions = 'actions';
+}
diff --git a/core/modules/navigation/templates/top-bar.html.twig b/core/modules/navigation/templates/top-bar.html.twig
index c840fd6b6647084fc75f30d548f6abc7635145ec..b294ecfaf2062fde91a8bc5c09cd5c2ea7177278 100644
--- a/core/modules/navigation/templates/top-bar.html.twig
+++ b/core/modules/navigation/templates/top-bar.html.twig
@@ -4,17 +4,25 @@
  * Default theme implementation for the navigation top bar.
  *
  * Available variables:
- * - local_tasks: The local tasks for the current route.
+ * - element: The top bar render element.
+ * - tools: The tools region of the top bar.
+ * - context: The context region of the top bar.
+ * - actions: The actions region of the top bar.
  *
  * @ingroup themeable
  */
 #}
 {% set attributes = create_attribute() %}
-{% if local_tasks %}
-  {% set attributes = attributes.setAttribute('data-offset-top', '') %}
-  <div {{ attributes.addClass('top-bar').setAttribute('data-drupal-admin-styles', '') }}>
-    <div class="top-bar__content">
-      {{ local_tasks }}
+<div {{ attributes.addClass('top-bar').setAttribute('data-drupal-admin-styles', '') }}>
+  <div class="top-bar__content">
+    <div class="top-bar__tools">
+      {{- tools -}}
+    </div>
+    <div class="top-bar__context">
+      {{- context -}}
+    </div>
+    <div class="top-bar__actions">
+      {{- actions -}}
     </div>
   </div>
-{% endif %}
+</div>
diff --git a/core/modules/navigation/tests/navigation_test/src/Plugin/TopBarItem/TopBarItemInstantiation.php b/core/modules/navigation/tests/navigation_test/src/Plugin/TopBarItem/TopBarItemInstantiation.php
new file mode 100644
index 0000000000000000000000000000000000000000..dd0a6de715938faac579193cb795e98e21cae882
--- /dev/null
+++ b/core/modules/navigation/tests/navigation_test/src/Plugin/TopBarItem/TopBarItemInstantiation.php
@@ -0,0 +1,28 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\navigation_test\Plugin\TopBarItem;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\navigation\Attribute\TopBarItem;
+use Drupal\navigation\TopBarItemBase;
+use Drupal\navigation\TopBarRegion;
+
+#[TopBarItem(
+  id: 'test_item',
+  region: TopBarRegion::Actions,
+  label: new TranslatableMarkup('Test Item'),
+)]
+class TopBarItemInstantiation extends TopBarItemBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build(): array {
+    return [
+      '#markup' => 'Top Bar Item',
+    ];
+  }
+
+}
diff --git a/core/modules/navigation/tests/src/Functional/NavigationTopBarTest.php b/core/modules/navigation/tests/src/Functional/NavigationTopBarTest.php
index 84fc5a0acdc17774c27846130a5bf8184a7c92ae..18b4d5bac38ba281bcd35ed48ab301cff0842b1f 100644
--- a/core/modules/navigation/tests/src/Functional/NavigationTopBarTest.php
+++ b/core/modules/navigation/tests/src/Functional/NavigationTopBarTest.php
@@ -79,15 +79,15 @@ public function testTopBarVisibility(): void {
     $this->drupalGet($this->node->toUrl());
 
     // Top Bar is not visible if the feature flag module is disabled.
-    $this->assertSession()->elementNotExists('xpath', "//div[contains(@class, 'top-bar__content')]/button/span");
+    $this->assertSession()->elementNotExists('xpath', "//div[contains(@class, 'top-bar__content')]/div[contains(@class, 'top-bar__actions')]/button/span");
     $this->assertSession()->elementExists('xpath', '//div[@id="block-tabs"]');
 
     \Drupal::service('module_installer')->install(['navigation_top_bar']);
 
     // Top Bar is visible once the feature flag module is enabled.
     $this->drupalGet($this->node->toUrl());
-    $this->assertSession()->elementExists('xpath', "//div[contains(@class, 'top-bar__content')]/button/span");
-    $this->assertSession()->elementTextEquals('xpath', "//div[contains(@class, 'top-bar__content')]/button/span", 'More actions');
+    $this->assertSession()->elementExists('xpath', "//div[contains(@class, 'top-bar__content')]/div[contains(@class, 'top-bar__actions')]/button/span");
+    $this->assertSession()->elementTextEquals('xpath', "//div[contains(@class, 'top-bar__content')]/div[contains(@class, 'top-bar__actions')]/button/span", 'More actions');
     $this->assertSession()->elementNotExists('xpath', '//div[@id="block-tabs"]');
 
     // Find all the dropdown links and check if the top bar is there as well.
@@ -95,8 +95,8 @@ public function testTopBarVisibility(): void {
 
     foreach ($toolbar_links->findAll('css', 'li') as $toolbar_link) {
       $this->clickLink($toolbar_link->getText());
-      $this->assertSession()->elementExists('xpath', "//div[contains(@class, 'top-bar__content')]/button/span");
-      $this->assertSession()->elementTextEquals('xpath', "//div[contains(@class, 'top-bar__content')]/button/span", 'More actions');
+      $this->assertSession()->elementExists('xpath', "//div[contains(@class, 'top-bar__content')]/div[contains(@class, 'top-bar__actions')]/button/span");
+      $this->assertSession()->elementTextEquals('xpath', "//div[contains(@class, 'top-bar__content')]/div[contains(@class, 'top-bar__actions')]/button/span", 'More actions');
       $this->assertSession()->elementNotExists('xpath', '//div[@id="block-tabs"]');
     }
   }
diff --git a/core/modules/navigation/tests/src/Unit/TopBarItemBaseTest.php b/core/modules/navigation/tests/src/Unit/TopBarItemBaseTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..27cc1f24dad31d3ac0aefe6aa75f3ccb6fd8bb01
--- /dev/null
+++ b/core/modules/navigation/tests/src/Unit/TopBarItemBaseTest.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Tests\navigation\Unit;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\navigation\TopBarRegion;
+use Drupal\navigation_test\Plugin\TopBarItem\TopBarItemInstantiation;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\navigation\TopBarItemBase
+ *
+ * @group navigation
+ */
+class TopBarItemBaseTest extends UnitTestCase {
+
+  /**
+   * @covers ::label
+   * @covers ::region
+   */
+  public function testTopBarItemBase(): void {
+    $definition = [
+      'label' => new TranslatableMarkup('label'),
+      'region' => TopBarRegion::Tools,
+    ];
+
+    $top_bar_item_base = new TopBarItemInstantiation([], 'test_top_bar_item_base', $definition);
+
+    $this->assertEquals($definition['label'], $top_bar_item_base->label());
+    $this->assertEquals($definition['region'], $top_bar_item_base->region());
+  }
+
+}
diff --git a/core/modules/navigation/tests/src/Unit/TopBarItemManagerTest.php b/core/modules/navigation/tests/src/Unit/TopBarItemManagerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..fb61242b65fce92de5173a091888fb384a9db0a8
--- /dev/null
+++ b/core/modules/navigation/tests/src/Unit/TopBarItemManagerTest.php
@@ -0,0 +1,93 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Tests\navigation\Unit;
+
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\navigation\TopBarItemManager;
+use Drupal\navigation\TopBarItemManagerInterface;
+use Drupal\navigation\TopBarRegion;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\navigation\TopBarItemManager
+ *
+ * @group navigation
+ */
+class TopBarItemManagerTest extends UnitTestCase {
+
+  use StringTranslationTrait;
+
+  /**
+   * The top bar item manager under test.
+   *
+   * @var \Drupal\navigation\TopBarItemManagerInterface
+   */
+  protected TopBarItemManagerInterface $manager;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->getStringTranslationStub());
+    \Drupal::setContainer($container);
+
+    $cache_backend = $this->prophesize(CacheBackendInterface::class);
+    $module_handler = $this->prophesize(ModuleHandlerInterface::class);
+    $this->manager = new TopBarItemManager(new \ArrayObject(), $cache_backend->reveal(), $module_handler->reveal());
+
+    $discovery = $this->prophesize(DiscoveryInterface::class);
+    // Specify the 'broken' block, as well as 3 other blocks with admin labels
+    // that are purposefully not in alphabetical order.
+    $discovery->getDefinitions()->willReturn([
+      'tools' => [
+        'label' => $this->t('Tools'),
+        'region' => TopBarRegion::Tools,
+      ],
+      'context' => [
+        'admin_label' => $this->t('Context'),
+        'region' => TopBarRegion::Context,
+      ],
+      'actions' => [
+        'label' => $this->t('Actions'),
+        'region' => TopBarRegion::Actions,
+      ],
+      'more_actions' => [
+        'label' => $this->t('More Actions'),
+        'region' => TopBarRegion::Actions,
+      ],
+    ]);
+    // Force the discovery object onto the block manager.
+    $property = new \ReflectionProperty(TopBarItemManager::class, 'discovery');
+    $property->setValue($this->manager, $discovery->reveal());
+  }
+
+  /**
+   * @covers ::getDefinitions
+   */
+  public function testDefinitions(): void {
+    $definitions = $this->manager->getDefinitions();
+    $this->assertSame(['tools', 'context', 'actions', 'more_actions'], array_keys($definitions));
+  }
+
+  /**
+   * @covers ::getDefinitionsByRegion
+   */
+  public function testGetDefinitionsByRegion(): void {
+    $tools = $this->manager->getDefinitionsByRegion(TopBarRegion::Tools);
+    $this->assertSame(['tools'], array_keys($tools));
+    $context = $this->manager->getDefinitionsByRegion(TopBarRegion::Context);
+    $this->assertSame(['context'], array_keys($context));
+    $actions = $this->manager->getDefinitionsByRegion(TopBarRegion::Actions);
+    $this->assertSame(['actions', 'more_actions'], array_keys($actions));
+  }
+
+}