diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 8677c72..c7a647d 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -742,12 +742,14 @@ function shortcut_toolbar() {
 
   $items['shortcuts'] = array(
     'tab' => array(
-      'title' => t('Shortcuts'),
-      'href' => 'admin/config/user-interface/shortcut',
-      'html' => FALSE,
-      'attributes' => array(
-        'title' => t('Shortcuts'),
-        'class' => array('icon', 'icon-shortcut'),
+      '#title' => t('Shortcuts'),
+      '#href' => 'admin/config/user-interface/shortcut',
+      '#options' => array(
+        'html' => FALSE,
+        'attributes' => array(
+          'title' => t('Shortcuts'),
+          'class' => array('icon', 'icon-shortcut'),
+        ),
       ),
     ),
     'tray' => $links_tray,
diff --git a/core/modules/toolbar/templates/toolbar.twig b/core/modules/toolbar/templates/toolbar.twig
index c2181df..e72bc97 100644
--- a/core/modules/toolbar/templates/toolbar.twig
+++ b/core/modules/toolbar/templates/toolbar.twig
@@ -5,6 +5,7 @@
  *
  * Available variables:
  *
+ * - tab_heading: Translated header for the Tabs section.
  * - tabs: Themed links for the top level tabs.
  * - trays: An array of trays. It contains:
  *   - content: The themed tray content.
@@ -25,6 +26,7 @@
 
 <nav id="{{ attributes.id }}" class="{{ attributes.class }}"{{ attributes }}>
   <!-- Tabs -->
+  <h2 class="element-invisible">{{ tab_heading }}</h2>
   {{ tabs }}
 
   <!-- Trays -->
diff --git a/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module b/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module
index cadddc9..fa09015 100644
--- a/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module
+++ b/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module
@@ -6,21 +6,23 @@
  */
 
 /**
- * Um
+ * Implements hook_toolbar().
  */
 function toolbar_test_toolbar() {
   $tray_items = array(
-    l('link 1', '<front>'),
-    l('link 2', '<front>'),
-    l('link 3', '<front>'),
+    l(t('link 1'), '<front>'),
+    l(t('link 2'), '<front>'),
+    l(t('link 3'), '<front>'),
   );
   $items['testing'] = array(
     'tab' => array(
-      'title' => t('Test tab'),
-      'href' => '',
-      'html' => FALSE,
-      'attributes' => array(
-        'title' => t('Test tab'),
+      '#title' => t('Test tab'),
+      '#href' => '',
+      '#options' => array(
+        'html' => FALSE,
+        'attributes' => array(
+          'title' => t('Test tab'),
+        ),
       ),
     ),
     'tray' => array(
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index e543326..5e76400 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -145,6 +145,10 @@ function toolbar_page_build(&$page) {
  */
 function toolbar_pre_render($toolbar) {
   $toolbar = array_merge($toolbar, toolbar_view());
+  $toolbar['tab_heading'] = array(
+    '#type' => 'markup',
+    '#markup' => t('Toolbar'),
+  );
   return $toolbar;
 }
 
@@ -160,12 +164,13 @@ function template_preprocess_toolbar(&$variables) {
     // The 'overlay-displace-top' class pushes the overlay down, so it appears
     // below the toolbar.
     'class' => array('toolbar', 'overlay-displace-top'),
-    'role' => 'navigation'
+    'role' => 'navigation',
   ));
 
   // Provide a convenience variable for the themed tabs.
   $variables['toolbar']['tabs']['#attributes']['class'][] = 'overlay-displace-top';
   $variables['tabs'] = $variables['toolbar']['tabs'];
+  $variables['tab_heading'] = $variables['toolbar']['tab_heading'];
 
   // Place the tabs in a top-level variable so that attribute information
   // can be associated with each one.
@@ -212,12 +217,14 @@ function toolbar_toolbar() {
   // The 'Home' tab is a simple link, with no corresponding tray.
   $items['home'] = array(
     'tab' => array(
-      'title' => t('Home'),
-      'href' => '<front>',
-      'html' => FALSE,
-      'attributes' => array(
-        'title' => t('Home page'),
-        'class' => array('icon', 'icon-home'),
+      '#title' => t('Home'),
+      '#href' => '<front>',
+      '#options' => array(
+        'html' => FALSE,
+        'attributes' => array(
+          'title' => t('Home page'),
+          'class' => array('icon', 'icon-home'),
+        ),
       ),
     ),
     'weight' => -20,
@@ -249,12 +256,14 @@ function toolbar_toolbar() {
 
   $items['administration'] = array(
     'tab' => array(
-      'title' => t('Menu'),
-      'href' => 'admin',
-      'html' => FALSE,
-      'attributes' => array(
-        'title' => t('Admin menu'),
-        'class' => array('icon', 'icon-menu'),
+      '#title' => t('Menu'),
+      '#href' => 'admin',
+      '#options' => array(
+        'html' => FALSE,
+        'attributes' => array(
+          'title' => t('Admin menu'),
+          'class' => array('icon', 'icon-menu'),
+        ),
       ),
     ),
     'tray' => $menu,
@@ -269,82 +278,106 @@ function toolbar_toolbar() {
  *
  * @return
  *   A renderable arrray, with two children:
- *   - 'tabs': an array of links, rendered by theme('links').
+ *   - 'tabs': an array of render elements, with default type 'link'.
  *   - 'trays': an array of render elements displayed when the corresponding tab
  *     is activated.
  */
 function toolbar_view() {
 
-  $build = array('#theme' => 'toolbar');
-  $build['#attached']['library'][] = array('toolbar', 'toolbar');
+  // Get toolbar items from all modules that implement hook_toolbar().
+  $toolbar_groups = module_invoke_all('toolbar');
 
-  // Get the configured breakpoint to switch from vertical to horizontal
-  // toolbar presentation.
-  $breakpoints = entity_load('breakpoint_group', 'module.toolbar.toolbar');
-  if (!empty($breakpoints)) {
-    $media_queries = array();
-    $media_queries['toolbar']['breakpoints'] = array_map(
-      function($object) {return $object->mediaQuery;},
-      $breakpoints->breakpoints);
+  // @todo Maybe define a new type with these defaults using
+  // hook_element_info().
+  $tab_defaults = array(
+    '#type' => 'link',
+    '#title' => '',
+    '#href' => '',
+    '#options' => array(
+      'html' => FALSE,
+      'attributes' => new Attribute(),
+    ),
+  );
 
-    $build['#attached']['js'][] = array(
-      'data' => $media_queries,
-      'type' => 'setting',
-    );
-    // // Load the breakpoints for toolbar.
-    foreach ($breakpoints->breakpoints as $key => $breakpoint) {
-      $build['#attached']['js'][0]['data']['toolbar']['breakpoints'][$key] = $breakpoint->mediaQuery;
+  // For each $group, $toolbar_groups[$group] is an array with keys 'tab'
+  // (required), 'tray', and 'weight'. Keep this structure until we invoke
+  // hook_toolbar_alter(), so that other modules can easily change the
+  // 'weight' values. If 'tray' is defined, then add attributes to the tab.
+  foreach ($toolbar_groups as $group => &$items) {
+    if (!array_key_exists('tab', $items)) {
+      continue;
+    }
+    $tab = &$items['tab'];
+    // Merge in the defaults.
+    // @todo Maybe merge in $tab_defaults['options'] separately. Or use
+    // array_merge_recursive().
+    $tab += $tab_defaults;
+    // Register a tray if one is associated with this tab.
+    if (array_key_exists('tray', $items) && !empty($items['tray'])) {
+      // Provide an id, a data attribute linking each tab to the corresponding
+      // tray and aria information. If another module defines these in
+      // hook_toolbar(), it had better know what it is doing.
+      $tab['#options']['attributes']['id'] = 'toolbar-tab-' . $group;
+      $tab['#options']['attributes']['data-toolbar-tray'] = $group;
+      $tab['#options']['attributes']['aria-owns'] = 'toolbar-tray-' . $group;
+      $tab['#options']['attributes']['role'] = 'button';
+      $tab['#options']['attributes']['aria-pressed'] = 'false';
     }
   }
+  unset($items);
 
-  // Get toolbar items from all modules that implement hook_toolbar() or
-  // hook_toolbar_alter().
-  $toolbar_groups = module_invoke_all('toolbar');
+  // Modules can make changes using hook_toolbar_alter(). Note that
+  // $toolbar_groups has the same structure as before; the only change is that
+  // we have added some attributes.
   drupal_alter('toolbar', $toolbar_groups);
   uasort($toolbar_groups, 'drupal_sort_weight');
 
-  // Build the tabs and trays from the toolbar groups.
+  // Start to build the render array.
+  $build = array('#theme' => 'toolbar');
   $build['trays'] = array();
   $build['tabs'] = array(
-    '#theme' => 'links',
-    '#links' => array(),
+    '#type' => 'ul',
+    '#items' => array(),
+    '#theme' => 'item_list',
     '#attributes' => array(
       'class' => array('bar', 'clearfix'),
     ),
-    '#heading' => array('text' => t('Toolbar'), 'level' => 'h2', 'class' => 'element-invisible'),
-  );
-  $tab_defaults = array(
-    'title' => '',
-    'href' => '',
-    'html' => FALSE,
-    'attributes' => new Attribute(),
   );
 
+  // Add the tabs and trays from the toolbar groups.
   foreach ($toolbar_groups as $group => $items) {
-    if ($tab = $items['tab']) {
-      // Merge in the defaults.
-      $tab += $tab_defaults;
-    }
-    // Register a tray if one is associated with this tab.
-    if (!empty($items['tray'])) {
-      // Provide an id, a data attribute linking each tab to the corresponding
-      // tray and aria information.
-      $tab['attributes']['id'] = 'toolbar-tab-' . $group;
-      $tab['attributes']['data-toolbar-tray'] = $group;
-      $tab['attributes']['aria-owns'] = 'toolbar-tray-' . $group;
-      $tab['attributes']['role'] = 'button';
-      $tab['attributes']['aria-pressed'] = 'false';
-
-      if (array_key_exists($group, $build['trays'])) {
-        array_merge($build['trays'][$group], $items['tray']);
-      }
-      else {
-        // Assign the tray to the build.
-        $build['trays'][$group] = $items['tray'];
-      }
+    if (!array_key_exists('tab', $items)) {
+      continue;
     }
     // Assign the tabs to the build.
-    $build['tabs']['#links'][$group] = $tab;
+    $build['tabs']['#items'][$group] = $items['tab'];
+    if (array_key_exists('tray', $items) && !empty($items['tray'])) {
+      // Assign the tray to the build.
+      $build['trays'][$group] = $items['tray'];
+    }
+  }
+
+  // Attach the toolbar library.
+  $build['#attached']['library'][] = array('toolbar', 'toolbar');
+
+  // Get the configured breakpoints to switch from vertical to horizontal
+  // toolbar presentation.
+  $breakpoints = entity_load('breakpoint_group', 'module.toolbar.toolbar');
+  if (!empty($breakpoints)) {
+    $media_queries = array();
+    $media_queries['toolbar']['breakpoints'] = array_map(
+      function($object) {return $object->mediaQuery;},
+      $breakpoints->breakpoints
+    );
+
+    $build['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => $media_queries,
+    );
+    // Load the breakpoints for toolbar.
+    // foreach ($breakpoints->breakpoints as $key => $breakpoint) {
+    //   $build['#attached']['js'][0]['data']['toolbar']['breakpoints'][$key] = $breakpoint->mediaQuery;
+    // }
   }
 
   return $build;
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 7dabb6d..7cc4bca 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -3040,12 +3040,14 @@ function user_toolbar() {
 
   $items['user'] = array(
     'tab' => array(
-      'title' => user_format_name($user),
-      'href' => 'user',
-      'html' => FALSE,
-      'attributes' => array(
-        'title' => t('My account'),
-        'class' => array('icon', 'icon-user'),
+      '#title' => user_format_name($user),
+      '#href' => 'user',
+      '#options' => array(
+        'html' => FALSE,
+        'attributes' => array(
+          'title' => t('My account'),
+          'class' => array('icon', 'icon-user'),
+        ),
       ),
     ),
     'tray' => $user_tray,
