diff --git a/core/modules/contact/src/CategoryListBuilder.php b/core/modules/contact/src/CategoryListBuilder.php
index 37169ff..b0fe187 100644
--- a/core/modules/contact/src/CategoryListBuilder.php
+++ b/core/modules/contact/src/CategoryListBuilder.php
@@ -32,13 +32,14 @@ public function buildHeader() {
    * {@inheritdoc}
    */
   public function buildRow(EntityInterface $entity) {
-    $row['category'] = $this->getLabel($entity);
     // Special case the personal category.
     if ($entity->id() == 'personal') {
+      $row['category'] = $this->getLabel($entity);
       $row['recipients'] = t('Selected user');
       $row['selected'] = t('No');
     }
     else {
+      $row['category'] = $this->l($this->getLabel($entity),'contact.site_page_category', array('contact_category' => $entity->id()));
       $row['recipients'] = String::checkPlain(implode(', ', $entity->recipients));
       $default_category = \Drupal::config('contact.settings')->get('default_category');
       $row['selected'] = ($default_category == $entity->id() ? t('Yes') : t('No'));
@@ -46,4 +47,30 @@ public function buildRow(EntityInterface $entity) {
     return $row + parent::buildRow($entity);
   }
 
+  /**
+   * Renders a link to a route given a route name and its parameters.
+   *
+   * @see \Drupal\Core\Utility\LinkGeneratorInterface::generate() for details
+   *   on the arguments, usage, and possible exceptions.
+   *
+   * @return string
+   *   An HTML string containing a link to the given route and parameters.
+   */
+  protected function l($text, $route_name, array $parameters = array(), array $options = array()) {
+    return $this->linkGenerator()->generate($text, $route_name, $parameters, $options);
+  }
+
+  /**
+   * Returns the link generator.
+   *
+   * @return \Drupal\Core\Utility\LinkGeneratorInterface
+   *   The link generator
+   */
+  protected function linkGenerator() {
+    if (!isset($this->linkGenerator)) {
+      $this->linkGenerator = \Drupal::linkGenerator();
+    }
+    return $this->linkGenerator;
+  }
+
 }
diff --git a/core/modules/contact/src/Plugin/Block/ContactNavigationBlock.php b/core/modules/contact/src/Plugin/Block/ContactNavigationBlock.php
new file mode 100644
index 0000000..8bf8bdb
--- /dev/null
+++ b/core/modules/contact/src/Plugin/Block/ContactNavigationBlock.php
@@ -0,0 +1,244 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\contact\Plugin\Block\ContactNavigationBlock.
+ */
+
+namespace Drupal\contact\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Component\Utility\String;
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
+use Drupal\Core\Form\FormBuilderInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a 'Contact categories' block.
+ *
+ * @Block(
+ *   id = "contact_navigation",
+ *   admin_label = @Translation("Contact categories"),
+ *   category = @Translation("Menus")
+ * )
+ */
+class ContactNavigationBlock extends BlockBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The contact category storage.
+   *
+   * @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
+   */
+  protected $storage;
+
+  /**
+   * The form builder.
+   *
+   * @var \Drupal\Core\Form\FormBuilderInterface
+   */
+  protected $formBuilder;
+
+  /**
+   * Constructs a new ContactNavigationBlock instance.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $storage
+   *   The contact category storage.
+   * @param $form_builder \Drupal\Core\Form\FormBuilderInterface
+   *   The form builder.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, ConfigEntityStorageInterface $storage, FormBuilderInterface $form_builder) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->storage = $storage;
+    $this->formBuilder = $form_builder;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity.manager')->getStorage('contact_category'),
+      $container->get('form_builder')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return array(
+      'categories' => array(),
+      'cache' => array('max_age' => Cache::PERMANENT)
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    // Even when the menu block renders to the empty string for a user, we want
+    // the cache tag for this menu to be set: whenever the menu is changed, this
+    // menu block must also be re-rendered for that user, because maybe a menu
+    // link that is accessible for that user has been added.
+    $tags = array('contact_category' => array_keys($this->configuration['categories']));
+    return NestedArray::mergeDeep(parent::getCacheTags(), $tags);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getRequiredCacheContexts() {
+    // This blocks must be cached per role: different roles may have access to
+    // contact forms.
+    return array('cache_context.user.roles');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access(AccountInterface $account) {
+    // Only grant access to users with the 'access site-wide contact form'
+    // permission.
+    return $account->hasPermission('access site-wide contact form');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function blockForm($form, &$form_state) {
+    $form['categories'] = array(
+      '#type' => 'table',
+      '#header' => array(
+        'label' => $this->t('Category name'),
+        'display' => $this->t('Display'),
+        'weight' => $this->t('Weight'),
+      ),
+      '#empty' => $this->t('There is no contact categories yet. Create one.'),
+      '#tabledrag' => array(
+        array(
+          'action' => 'order',
+          'relationship' => 'sibling',
+          'group' => 'weight',
+        ),
+      ),
+    );
+
+    $categories = $this->configuration['categories'];
+    $rows = array();
+    $min_weight = 0;
+    /** @var $category \Drupal\contact\CategoryInterface */
+    foreach ($this->storage->loadMultiple() as $id => $category) {
+      // Do not list personal category.
+      if ($id == 'personal') {
+        continue;
+      }
+
+      $row_label = $category->label();
+      $row_weight = $category->get('weight');
+      $row_display = TRUE;
+
+      if ($categories) {
+        // Display only selected categories by default if there are any.
+        $row_display = isset($categories[$id]);
+        // Find lowest weight to display selected categories first.
+        if ($min_weight > $row_weight) {
+          $min_weight = $row_weight;
+        }
+      }
+      $row = array(
+        'label' => array('#markup' => String::checkPlain($row_label)),
+        'display' => array(
+          '#type' => 'checkbox',
+          '#default_value' => $row_display,
+          '#title' => t('Display the @title', array('@title' => $row_label)),
+          '#title_display' => 'invisible',
+        ),
+        // Add weight column.
+        'weight' => array(
+          '#type' => 'weight',
+          '#title' => $this->t('Weight for @title', array('@title' => $row_label)),
+          '#title_display' => 'invisible',
+          '#default_value' => $row_weight,
+          '#attributes' => array('class' => array('weight')),
+        ),
+      );
+      $row['#attributes']['class'][] = 'draggable';
+      $row['#weight'] = $row_weight;
+      $rows[$category->id()] = $row;
+    }
+
+    if ($categories) {
+      // Move selected categories to the top of the list.
+      $min_weight = $min_weight - count($categories);
+      foreach ($categories as $id => $data) {
+        if (isset($rows[$id])) {
+          $rows[$id]['#weight'] = $min_weight;
+          $rows[$id]['weight']['#default_value'] = $min_weight++;
+        }
+      }
+    }
+
+    uasort($rows, '\Drupal\Component\Utility\SortArray::sortByWeightProperty');
+    $form['categories'] += $rows;
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockValidate($form, &$form_state) {
+    $categories = array();
+    foreach ($form_state['values']['categories'] as $id => $value) {
+      if ($value['display']) {
+        $categories[$id] = $value['weight'];
+      }
+    }
+    if (empty($categories)) {
+      $this->formBuilder->setErrorByName('categories', $form_state, $this->t('At least one category should be selected.'));
+    }
+    $form_state['values']['categories'] = $categories;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockSubmit($form, &$form_state) {
+    $this->configuration['categories'] = $form_state['values']['categories'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    $links = array();
+    /** @var $category \Drupal\contact\CategoryInterface */
+    foreach ($this->storage->loadMultiple(array_keys($this->configuration['categories'])) as $id => $category) {
+      $links[$id] = array(
+        '#type' => 'link',
+        '#title' => $category->label(),
+        '#route_name' => 'contact.site_page_category',
+        '#route_parameters' => array('contact_category' => $id),
+      );
+    }
+    return array(
+      '#theme' => 'item_list__contact',
+      '#items' => $links,
+    );
+  }
+
+}
