diff --git a/menu_example/menu_example.info.yml b/menu_example/menu_example.info.yml
new file mode 100644
index 0000000..e9f6e4e
--- /dev/null
+++ b/menu_example/menu_example.info.yml
@@ -0,0 +1,7 @@
+name: Menu Example
+type: module
+description: 'An example module showing the main steps to define and handling menu links in Drupal 8 '
+package: 'Example modules'
+core: 8.x
+dependencies:
+  - drupal:examples
diff --git a/menu_example/menu_example.links.menu.yml b/menu_example/menu_example.links.menu.yml
new file mode 100644
index 0000000..bcfc9f1
--- /dev/null
+++ b/menu_example/menu_example.links.menu.yml
@@ -0,0 +1,92 @@
+# This file links a menu link with route_name.
+#
+# 'title' key is only key required.
+#
+# 'description' is  is shown either as a tooltip on the item or in the admin UI
+# as the description of the option on the page/
+#
+# 'weight' is used to order the items (higher weights get placed towards the
+# end of the menu among items on the same level).
+#
+# 'route_name' is used to link menu link to corresponding route.
+#
+# 'parent' is used to put item into the menu hierarchy by referring to the
+# parent menu link name.
+#
+examples.menu_example:
+  title: 'Menu Example'
+  description: 'Simplest possible menu type, and the parent menu entry for others'
+  expanded: 1
+  route_name: examples.menu_example
+
+examples.menu_example.alternate_menu:
+  title: 'Menu Example: Menu in alternate menu'
+   #If menu_name is omitted, the "Tools" menu will be used.
+  menu_name: 'main'
+  route_name: examples.menu_example.alternate_menu
+
+examples.menu_example.permissioned:
+  title: 'Permissioned Example'
+  parent: examples.menu_example
+  expanded: 1
+  route_name: examples.menu_example.permissioned
+  weight: 10
+
+examples.menu_example.permissioned_controlled:
+  title: 'Permissioned Menu Item'
+  parent: examples.menu_example.permissioned
+  route_name: examples.menu_example.permissioned_controlled
+  weight: 10
+
+examples.menu_example.custom_access:
+  title: 'Custom Access Example'
+  parent: examples.menu_example
+  expanded: 1
+  route_name: examples.menu_example.custom_access
+  weight: -5
+
+examples.menu_example.custom_access_page:
+  title: 'Custom Access Menu Item'
+  parent: examples.menu_example.custom_access
+  route_name: examples.menu_example.custom_access_page
+
+examples.menu_example.route_only:
+  title: 'Route only example'
+  parent: examples.menu_example
+  route_name: examples.menu_example.route_only
+  weight: 20
+
+examples.menu_example.tabs:
+  title: 'Tabs'
+  description: 'Shows how to create primary and secondary tabs'
+  parent: examples.menu_example
+  route_name: examples.menu_example.tabs
+  weight: 30
+
+examples.menu_example.use_url_arguments:
+  title: 'URL Arguments'
+  description: 'The page callback can use the arguments provided after the path used as key'
+  parent: examples.menu_example
+  route_name: examples.menu_example.use_url_arguments
+  weight: 40
+
+examples.menu_example.title_callbacks:
+  title: 'Dynamic title'
+  description: 'The title of this menu item is dynamically generated'
+  parent: examples.menu_example
+  route_name: examples.menu_example.title_callbacks
+  weight: 50
+
+examples.menu_example.placeholder_argument:
+  title: Placeholder Arguments
+  description: ''
+  parent: 'examples.menu_example'
+  route_name: examples.menu_example.placeholder_argument
+  weight: 60
+
+example.menu_example.path_override:
+  title: Path Override
+  description: ''
+  parent: 'examples.menu_example'
+  route_name: example.menu_example.path_override
+  weight: 70
diff --git a/menu_example/menu_example.links.task.yml b/menu_example/menu_example.links.task.yml
new file mode 100644
index 0000000..b50df55
--- /dev/null
+++ b/menu_example/menu_example.links.task.yml
@@ -0,0 +1,53 @@
+# This file creates static local tasks (Tabs).
+# This file will be needed to place in module root.
+#
+# 'title' of the tab will show up on the user interface and tab.
+#
+# 'base_route' is the same as the name of the route where the "default" tab
+# appears. The base_route is used to group together related tabs.
+#
+# 'weight' is used to provide weights for the tabs if needed.
+# The tab whose route is the same as the base_route will by default
+# get a negative weight and appear on the left.
+#
+# 'parent_id' is used to create multi level of tabs.
+# To relate a tab to its parent use same name as parent_id as shown below in
+# examples.menu_example.tabs.secondary.
+#
+examples.menu_example.tabs:
+  route_name: examples.menu_example.tabs
+  title: Default primary tab
+  base_route: examples.menu_example.tabs
+
+examples.menu_example.tabs_second:
+  route_name: examples.menu_example.tabs_second
+  title: Second
+  base_route: examples.menu_example.tabs
+  weight: 2
+
+examples.menu_example.tabs_third:
+  route_name: examples.menu_example.tabs_third
+  title: Third
+  base_route: examples.menu_example.tabs
+  weight: 3
+
+examples.menu_example.tabs_fourth:
+  route_name: examples.menu_example.tabs_fourth
+  title: Fourth
+  base_route: examples.menu_example.tabs
+  weight: 4
+
+examples.menu_example.tabs.secondary:
+  route_name: examples.menu_example.tabs
+  title: Default secondary tab
+  parent_id: examples.menu_example.tabs
+
+examples.menu_example.tabs_default_second:
+  route_name: examples.menu_example.tabs_default_second
+  title: Second
+  parent_id: examples.menu_example.tabs
+
+examples.menu_example.tabs_default_third:
+  route_name: examples.menu_example.tabs_default_third
+  title: Third
+  parent_id: examples.menu_example.tabs
diff --git a/menu_example/menu_example.module b/menu_example/menu_example.module
new file mode 100644
index 0000000..0521971
--- /dev/null
+++ b/menu_example/menu_example.module
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @file
+ * Module file for menu_example_module.
+ */
+
+/**
+ * Drupal 7's hook_menu() is now Routing system in Drupal 8.
+ *
+ * Drupal 8's routing system is based on Symfony's routing system.
+ *
+ * A route is an entry Drupal 8's router table which contains a path attached
+ * to it. In drupal, a route is a path which is returns some response.
+ *
+ * When a path is requested, Drupal matches the request to a route
+ * and if route is match the content is returned else 404 is returned.
+ *
+ * The association of a path with a controller, coupled with parameter
+ * upcasting and access checking is now handled in the routing system.
+ *
+ * @link menu_example.routing.yml @endlink
+ * Drupal loads the routing file that is of the form module_name.routing.yml
+ * that it will use to define how Drupal will behave when a specific path
+ * is encountered. If you want to expose content or functionality on your own
+ * URIs on a site, routing file is an important part of your module.
+ * This can help provide functionality at specific URIs of a website or just
+ * modify or augment existing functionality.
+ * @see https://www.drupal.org/docs/8/api/routing-system/structure-of-routes
+ *
+ * @link menu_example.links.menu.yml @endlink
+ * In Drupal 8, menu links are specified in a static file named as
+ * module_name.links.menu.yml. This file uses a route_name to tie a route name
+ * to a menu link. These are the links which appear on tools block in UI.
+ * @see https://www.drupal.org/docs/8/api/menu-api/providing-module-defined-menu-links
+ *
+ * @link menu_example.links.task.yml @endlink
+ * To create menu tab entries (only up to 2 level), we make entries in a file
+ * named as module_name.links.task.yml. These are mostly used on administrative
+ * pages but frontend pages like user pages or the registration/login/new
+ * password pages also use local tasks.
+ * @see https://www.drupal.org/docs/8/api/menu-api/providing-module-defined-local-tasks @endlink
+ */
diff --git a/menu_example/menu_example.permissions.yml b/menu_example/menu_example.permissions.yml
new file mode 100644
index 0000000..1bae26d
--- /dev/null
+++ b/menu_example/menu_example.permissions.yml
@@ -0,0 +1,5 @@
+# File contains permissions for the menu_example module.
+access protected menu example:
+  title: 'Access protected menu example'
+  description: 'Bypass access control when accessing menu example.'
+  restrict access: TRUE
diff --git a/menu_example/menu_example.routing.yml b/menu_example/menu_example.routing.yml
new file mode 100644
index 0000000..300925f
--- /dev/null
+++ b/menu_example/menu_example.routing.yml
@@ -0,0 +1,143 @@
+# This file contains routing entries which is then read by Drupal to match
+# a particular request which a corresponding path.  A particular route entry
+# is bound to the URI defined using 'path' key, the 'access content' permission
+# is checked on the accessing user and, if access is granted, the
+# MenuExampleController::{methodName} method is invoked and a page is displayed
+# with defined response.
+# '_controller' defines the controller class and it's method which Drupal's
+# autoload mechanism looks for, creating the response from.
+#
+examples.menu_example: # This is a route name.
+  path: '/examples/menu-example'
+  defaults:
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::description'
+    _title: 'Menu Example'
+  requirements:
+    _permission: 'access content'
+
+# This menu entry will appear as main menu tab instead of tools menu.
+# In menu_example.links.menu.yml we have used 'menu_name' as 'main' which links
+# the menu entry to main navigation menu.
+examples.menu_example.alternate_menu:
+  path: '/examples/menu-example-alternate-menu'
+  defaults:
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::alternateMenu'
+    _title: 'Menu Example: Menu in alternate menu'
+  requirements:
+    _permission: 'access content'
+
+# The menu entry demonstrates the use of permissions to restrict access
+# to a particular path until and unless the requirement is met.
+examples.menu_example.permissioned:
+  path: '/examples/menu-example/permissioned'
+  defaults:
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::permissioned'
+    _title: 'Permissioned Route Example'
+  requirements:
+    _permission: 'access content'
+
+# Only the user with the required permission will be able to access this route.
+examples.menu_example.permissioned_controlled:
+  path: '/examples/menu-example/permissioned/controlled'
+  defaults:
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::permissionedControlled'
+    _title: 'Permissioned Route'
+  requirements:
+    _permission: 'access protected menu example'
+
+# Sometimes just relying on permissions and/or roles is not sufficient
+# and you need to do custom access checking on routes.
+examples.menu_example.custom_access:
+  path: '/examples/menu-example/custom-access'
+  defaults:
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::customAccess'
+    _title: 'Custom Access Example'
+  requirements:
+    _permission: 'access content'
+
+# Custom access is called once this route is requested.
+# Check src/Access/RoleAccessCheck.php
+examples.menu_example.custom_access_page:
+  path: '/examples/menu-example/custom-access/page'
+  defaults:
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::customAccessPage'
+    _title: 'Custom Access Menu Item'
+  requirements:
+    _menu_example_role: 'TRUE'
+
+# This showcases how you define only a with no menu link entry.
+examples.menu_example.route_only:
+  path: '/examples/menu-example/route-only'
+  defaults:
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::routeOnly'
+    _title: 'Route only example'
+  requirements:
+    _permission: 'access content'
+
+# These type of routes can be used to create webservices.
+examples.menu_example.callback:
+  path: '/examples/menu-example/route-only/callback'
+  defaults:
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::routeOnlyCallback'
+    _title: 'Callback only'
+  requirements:
+    _permission: 'access content'
+
+# Drupal 8's routes may include placeholder elements which designate places
+# where the URL contains dynamic values. In the controller method, this value
+# is available when a variable with the same name is used in the controller
+# method. Matching the variable name is must. The {arg} element in the URL is
+# called a slug and is available as a $arg in the controller method.
+examples.menu_example.use_url_arguments:
+  path: 'examples/menu-example/use-url-arguments/{arg1}/{arg2}'
+  defaults:
+    _title: 'URL Arguments'
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::urlArgument'
+    # We provide default value to both arguments.
+    arg1: ''
+    arg2: ''
+  requirements:
+    _permission: 'access content'
+
+# Title of this menu entry will be altered by controller method defined by
+# key '_title_callback'.
+examples.menu_example.title_callbacks:
+  path: 'examples/menu-example/title-callbacks'
+  defaults:
+    _title_callback: 'Drupal\menu_example\Controller\MenuExampleController::backTitle'
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::titleCallback'
+  requirements:
+    _permission: 'access content'
+
+# A menu item entry to demonstrate use of parameters in routes.
+examples.menu_example.placeholder_argument:
+  path: 'examples/menu-example/placeholder-argument'
+  defaults:
+    _title: 'Placeholder Arguments'
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::placeholderArgs'
+  requirements:
+    _permission: 'access content'
+
+# Parameters in routes can be used as placeholders arguments too.
+examples.menu_example.placeholder_argument.display:
+  path: 'examples/menu-example/placeholder-argument/{arg}/display'
+  defaults:
+    _title: 'Placeholder Arguments'
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::placeholderArgsDisplay'
+  requirements:
+    arg: \d+
+    _permission: 'access content'
+
+# Any route defined here can be altered. We can do so by defining a RouteSubscriber!
+example.menu_example.path_override:
+  path: 'examples/menu-example/menu-original-path'
+  defaults:
+    _title: 'Menu path that will be altered'
+    _controller: '\Drupal\menu_example\Controller\MenuExampleController::pathOverride'
+  requirements:
+    _permission: 'access content'
+
+# Dynamic routes are implemented in a method. This method is added as a
+# 'route_callbacks'
+route_callbacks:
+  - '\Drupal\menu_example\Routing\MenuExampleDynamicRoutes::routes'
diff --git a/menu_example/menu_example.services.yml b/menu_example/menu_example.services.yml
new file mode 100644
index 0000000..0549543
--- /dev/null
+++ b/menu_example/menu_example.services.yml
@@ -0,0 +1,13 @@
+services:
+  menu_example.access_check.role:
+    class: Drupal\menu_example\Access\RoleAccessCheck
+    arguments: ['@current_user']
+    tags:
+      - { name: access_check, applies_to: _menu_example_role }
+      # _menu_example_role flaf is added to requirements section in
+      # menu_example.routing.yml to apply custom check routes.
+
+  menu_example.route_subscriber:
+    class: Drupal\menu_example\Routing\RouteSubscriber
+    tags:
+      - { name: event_subscriber }
diff --git a/menu_example/src/Access/RoleAccessCheck.php b/menu_example/src/Access/RoleAccessCheck.php
new file mode 100644
index 0000000..22578c0
--- /dev/null
+++ b/menu_example/src/Access/RoleAccessCheck.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Drupal\menu_example\Access;
+
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Routing\Access\AccessInterface;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Determines access to routes based on roles.
+ *
+ * To achieve this, we implement a class with AccessInterface and use that to
+ * check access.
+ *
+ * Our module is called menu_example, this file will be placed under
+ * menu_example/src/Access/CustomAccessCheck.php.
+ *
+ * The @link menu_example_services.yml @endlink contains entry for this service
+ * class.
+ *
+ * @see https://www.drupal.org/docs/8/api/routing-system/access-checking-on-routes
+ */
+class RoleAccessCheck implements AccessInterface {
+
+  /**
+   * Checks access.
+   *
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The currently logged in account.
+   *
+   * @return string
+   *   A \Drupal\Core\Access\AccessInterface constant value.
+   */
+  public function access(AccountInterface $account) {
+    // If the user is authenticated, return TRUE.
+    return AccessResult::allowedIf($account->isAuthenticated());
+  }
+
+}
diff --git a/menu_example/src/Controller/MenuExampleController.php b/menu_example/src/Controller/MenuExampleController.php
new file mode 100644
index 0000000..55e938b
--- /dev/null
+++ b/menu_example/src/Controller/MenuExampleController.php
@@ -0,0 +1,253 @@
+<?php
+
+namespace Drupal\menu_example\Controller;
+
+use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Link;
+use Drupal\examples\Utility\DescriptionTemplateTrait;
+
+/**
+ * Controller routines for menu example routes.
+ *
+ * The response of Drupal's HTTP Kernel system's request is generated by
+ * a piece of code called the controller.
+ *
+ * In Drupal 8, we use a controller class
+ * for placing those piece of codes in methods which responds to a route.
+ *
+ * This file will be placed at {module_name}/src/Controller directory. Route
+ * entries uses a key '_controller' to define the method called from controller
+ * class.
+ *
+ * @see https://www.drupal.org/docs/8/api/routing-system/introductory-drupal-8-routes-and-controllers-example
+ */
+class MenuExampleController extends ControllerBase {
+
+  use DescriptionTemplateTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getModuleName() {
+    return 'menu_example';
+  }
+
+  /**
+   * Page callback for the simplest introduction menu entry.
+   *
+   * The controller callback defined menu_examples.routing.yml file,
+   * maps the path 'examples/menu-example' to this method.
+   *
+   * @throws \InvalidArgumentException
+   */
+  public function basicInstructions() {
+    return [
+      $this->description(),
+    ];
+  }
+
+  /**
+   * Show a menu link in a menu other than the default "Navigation" menu.
+   */
+  public function alternateMenu() {
+    return [
+      '#markup' => $this->t('This will be in the Main menu instead of the default Tools menu'),
+    ];
+
+  }
+
+  /**
+   * A menu entry with simple permissions using 'access protected menu example'.
+   *
+   * @throws \InvalidArgumentException
+   */
+  public function permissioned() {
+    $link = Link::createFromRoute($this->t('examples/menu-example/permissioned/controlled'),
+      'examples.menu_example.permissioned_controlled')->toString();
+    return [
+      '#markup' => $this->t('A menu item that requires the "access protected menu example" permission is at @link', ['@link' => $link]),
+    ];
+  }
+
+  /**
+   * Only accessible when the user will be granted with required permission.
+   *
+   * The permission is defined in file menu_examples.permissions.yml.
+   */
+  public function permissionedControlled() {
+    return [
+      '#markup' => $this->t('This menu entry will not show and the page will not be accessible without the "access protected menu example" permission to current user.'),
+    ];
+  }
+
+  /**
+   * Demonstrates the use of custom access check in routes.
+   *
+   * @throws \InvalidArgumentException
+   *
+   * @see \Drupal\menu_example\Controller\MenuExampleController::customAccessPage()
+   */
+  public function customAccess() {
+    $link = Link::createFromRoute($this->t('examples/menu-example/custom-access/page'),
+      'examples.menu_example.custom_access_page')->toString();
+    return [
+      '#markup' => $this->t('A menu item that requires the user to posess a role of "authenticated" is at @link', ['@link' => $link]),
+    ];
+  }
+
+  /**
+   * Content will be displayed only if access check is satisfied.
+   *
+   * @see \Drupal\menu_example\Controller\MenuExampleController::customAccess()
+   */
+  public function customAccessPage() {
+    return [
+      '#markup' => $this->t('This menu entry will not be visible and access will result
+        in a 403 error unless the user has the "authenticated" role. This is
+        accomplished with a custom access check plugin.'),
+    ];
+  }
+
+  /**
+   * Only callback without a menu link.
+   *
+   * @throws \InvalidArgumentException
+   */
+  public function routeOnly() {
+    $link = Link::createFromRoute($this->t('examples/menu-example/route-only/callback'),
+      'examples.menu_example.callback')->toString();
+    return [
+      '#markup' => $this->t('A menu entry with no menu link is at @link', ['@link' => $link]),
+    ];
+  }
+
+  /**
+   * Such callbacks can be user for creating web services in Drupal 8.
+   */
+  public function routeOnlyCallback() {
+    return [
+      '#markup' => $this->t('The route entry has no corresponding menu links entry, so it provides a route without a menu link, but it is the same in every other way to the simplest example.'),
+    ];
+  }
+
+  /**
+   * @param string $path
+   *   Path/URL of menu item.
+   *
+   * @param string $title
+   *   Title of menu item.
+   *
+   * @return array
+   *   Controller response.
+   */
+  public function tabsPage($path, $title) {
+    $secondary = substr_count($path, '/') > 2 ? 'secondary ' : '';
+    return [
+      '#markup' => $this->t('This is the @secondary tab "@tabname" in the "basic tabs" example.', ['@secondary' => $secondary, '@tabname' => $title]),
+    ];
+  }
+
+  /**
+   * Demonstrates use of url arguments in for menu item.
+   *
+   * @param string $arg1
+   *   First argument of url.
+   * @param string $arg2
+   *   Second argument of url.
+   *
+   * @return array
+   *   Controller response.
+   *
+   * @see https://www.drupal.org/docs/8/api/routing-system/parameters-in-routes
+   */
+  public function urlArgument($arg1, $arg2) {
+    // Perpare link for single arguments.
+    $link = Link::createFromRoute($this->t('examples/menu-example/use-url-arguments/one'),
+      'examples.menu_example.use_url_arguments', ['arg1' => 'one'])->toString();
+
+    // Prepare link for multiple arguments.
+    $linktwo = Link::createFromRoute($this->t('examples/menu-example/use-url-arguments/one/two'),
+      'examples.menu_example.use_url_arguments', ['arg1' => 'one', 'arg2' => 'two'])->toString();
+
+    $markup = $this->t('This page demonstrates using arguments in the url. For example, access it with @link for single argument or @linktwo for two arguments in URL', ['@link' => $link, '@linktwo' => $linktwo]);
+
+    if (!empty($arg1)) {
+      $markup .= '<div>' . $this->t('Argument 1 = @arg', ['@arg' => $arg1]) . '</div>';
+    }
+    if (!empty($arg2)) {
+      $markup .= '<div>' . $this->t('Argument 2 = @arg', ['@arg' => $arg2]) . '</div>';
+    }
+
+    return [
+      '#markup' => $markup,
+
+    ];
+  }
+
+  /**
+   * Demonstrate generation of dynamic creation of page title.
+   *
+   * @see \Drupal\menu_example\Controller\MenuExampleController::backTitle()
+   */
+  public function titleCallback() {
+    return [
+      '#markup' => $this->t('The title of this page is dynamically changed by the title callback for this route defined in menu_example.routing.yml.'),
+    ];
+  }
+
+  /**
+   * Generates title dynamically.
+   *
+   * @see \Drupal\menu_example\Controller\MenuExampleController::titleCallback()
+   */
+  public function backTitle() {
+    $name = \Drupal::currentUser()->getDisplayName();
+    return [
+      '#markup' => $this->t('The new title is your username: @name', ['@name' => $name]),
+    ];
+  }
+
+  /**
+   * Demonstrates how you can provide a placeholder url arguments.
+   *
+   * @throws \InvalidArgumentException
+   *
+   * @see \Drupal\menu_example\Controller\MenuExampleController::placeholderArgsDisplay()
+   * @see https://www.drupal.org/docs/8/api/routing-system/using-parameters-in-routes
+   */
+  public function placeholderArgs() {
+    $link = Link::createFromRoute($this->t('examples/menu-example/placeholder-argument/3343/display'),
+      'examples.menu_example.placeholder_argument.display', ['arg' => 3343])->toString();
+    return [
+      '#markup' => $this->t('Demonstrate placeholders by visiting @link', ['@link' => $link]),
+    ];
+  }
+
+  /**
+   * Displays placeholder argument supplied in URL.
+   *
+   * @param int $arg
+   *   URL argument.
+   *
+   * @return array
+   *   URL argument.
+   *
+   * @see \Drupal\menu_example\Controller\MenuExampleController::placeholderArgs()
+   */
+  public function placeholderArgsDisplay($arg) {
+    return [
+      '#markup' => $arg,
+    ];
+
+  }
+
+  /**
+   * Demonstrate how one can alter the existing routes.
+   */
+  public function pathOverride() {
+    return [
+      '#markup' => $this->t('This menu item was created strictly to allow the RouteSubscriber class to have something to operate on. menu_example.routing.yml defined the path as examples/menu-example/menu-original-path. The alterRoutes() changes it to /examples/menu-example/menu-altered-path. You can try navigating to both paths and see what happens!'),
+    ];
+  }
+
+}
diff --git a/menu_example/src/Routing/MenuExampleDynamicRoutes.php b/menu_example/src/Routing/MenuExampleDynamicRoutes.php
new file mode 100644
index 0000000..ca75524
--- /dev/null
+++ b/menu_example/src/Routing/MenuExampleDynamicRoutes.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Drupal\menu_example\Routing;
+
+use Symfony\Component\Routing\Route;
+
+/**
+ * Defines dynamic routes for our tabs menu items.
+ *
+ * @see https://www.drupal.org/docs/8/api/routing-system/providing-dynamic-routes
+ */
+class MenuExampleDynamicRoutes {
+
+  /**
+   * Returns an array of route objects.
+   *
+   * @return \Symfony\Component\Routing\Route[]
+   *   An array of route objects.
+   */
+  public function routes() {
+    $routes = [];
+
+    $tabs = [
+      'tabs' => 'Default primary tab',
+      'tabs/second' => 'Second',
+      'tabs/third' => 'Third',
+      'tabs/fourth' => 'Fourth',
+      'tabs/default/second' => 'Second',
+      'tabs/default/third' => 'Third',
+    ];
+
+    foreach ($tabs as $path => $title) {
+      $machine_name = 'examples.menu_example.'. str_replace('/', '_', $path);
+      $routes[$machine_name] = new Route(
+        // Path to attach this route to:
+        '/examples/menu-example/' . $path,
+        // Route defaults:
+        [
+          '_controller' => '\Drupal\menu_example\Controller\MenuExampleController::tabsPage',
+          '_title' => $title,
+          'path' => $path,
+          'title' => $title,
+        ],
+        // Route requirements:
+        [
+          '_access' => 'TRUE',
+        ]
+      );
+    }
+
+    return $routes;
+  }
+
+}
diff --git a/menu_example/src/Routing/RouteSubscriber.php b/menu_example/src/Routing/RouteSubscriber.php
new file mode 100644
index 0000000..6f78dc6
--- /dev/null
+++ b/menu_example/src/Routing/RouteSubscriber.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Drupal\menu_example\Routing;
+
+use Drupal\Core\Routing\RouteSubscriberBase;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * Listens to the dynamic route events.
+ *
+ * The \Drupal\Core\Routing\RouteSubscriberBase class contains an event
+ * listener that listens to this event. We alter existing routes by
+ * implementing the alterRoutes(RouteCollection $collection) method of
+ * this class.
+ *
+ * @see https://www.drupal.org/docs/8/api/routing-system/altering-existing-routes-and-adding-new-routes-based-on-dynamic-ones
+ */
+class RouteSubscriber extends RouteSubscriberBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function alterRoutes(RouteCollection $collection) {
+    // Get the path from RouteCollection.
+    $route = $collection->get('example.menu_example.path_override');
+    // Set the new path.
+    $route->setPath('/examples/menu-example/menu-altered-path');
+    // Change title to indicate changes.
+    $route->setDefault('_title', 'Menu item altered by RouteSubscriber::alterRoutes');
+  }
+
+}
diff --git a/menu_example/templates/description.html.twig b/menu_example/templates/description.html.twig
new file mode 100644
index 0000000..953e17f
--- /dev/null
+++ b/menu_example/templates/description.html.twig
@@ -0,0 +1,17 @@
+{#
+
+Description text for the Menu Example.
+
+#}
+
+{% set link = path('examples.menu_example.route_only') %}
+
+{% trans %}
+
+<p>This page is displayed by the simplest (and base) menu example. Note that
+the title of the page is the same as the link title.
+You can also <a href="{{ link }}">visit a similar page with no menu link</a>.
+There are a number of examples here, from the most basic (like this one) to
+extravagant mappings of loaded placeholder arguments. Enjoy!</p>
+
+{% endtrans %}
diff --git a/menu_example/tests/src/Functional/MenuExampleTest.php b/menu_example/tests/src/Functional/MenuExampleTest.php
new file mode 100644
index 0000000..2edc343
--- /dev/null
+++ b/menu_example/tests/src/Functional/MenuExampleTest.php
@@ -0,0 +1,108 @@
+<?php
+
+namespace Drupal\Tests\menu_example\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+use Drupal\user\Entity\Role;
+use Drupal\Core\Url;
+
+/**
+ * Test the functionality for the menu Example.
+ *
+ * @ingroup menu_example
+ *
+ * @group menu_example
+ * @group examples
+ */
+class MenuExampleTest extends BrowserTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['menu_example'];
+  /**
+   * The installation profile to use with this test.
+   *
+   * @var string
+   */
+  protected $profile = 'minimal';
+
+  /**
+   * Runs different tests for menu example.
+   */
+  public function testMenuExample() {
+    $this->assertSession()->pageTextContains('Menu Example');
+    $this->clickLink(t('Menu Example'));
+    $this->assertSession()->pageTextContains(t('This page is displayed by the simplest (and base) menu example'));
+
+    // Create a user with permissions to access protected menu entry.
+    $web_user = $this->drupalCreateUser();
+    // Use custom overridden drupalLogin function to verify the user is logged
+    // in.
+    $this->drupalLogin($web_user);
+    // Check that our title callback changing /user dynamically is working.
+    $this->assertSession()->pageTextContains(t("@name", ['@name' => $web_user->getUsername()]));
+
+    // Now start testing other menu entries.
+    $this->drupalGet(Url::fromRoute('examples.menu_example'));
+    $this->clickLink(t('Custom Access Example'));
+    $this->assertSession()->pageTextContains(t('Custom Access Example'));
+    $this->drupalGet(Url::fromRoute('examples.menu_example.custom_access_page'));
+    $this->assertSession()->statusCodeEquals(200);
+    // Logout user to check denial of access.
+    $this->drupalLogout();
+    $this->drupalGet(Url::fromRoute('examples.menu_example.custom_access_page'));
+    $this->assertSession()->statusCodeEquals(403);
+
+    // Check 'Permission Example' menu entry.
+    $this->drupalLogin($web_user);
+    $this->drupalGet(Url::fromRoute('examples.menu_example.permissioned'));
+    $this->assertSession()->pageTextContains(t('Permissioned Example'));
+    $this->clickLink('examples/menu-example/permissioned/controlled');
+    $this->assertSession()->statusCodeEquals(403);
+    // Check access with appropriate permissions.
+    $this->grantPermissions(Role::load(Role::AUTHENTICATED_ID), ['access protected menu example']);
+    $this->drupalGet(Url::fromRoute('examples.menu_example.permissioned_controlled'));
+    $this->assertSession()->statusCodeEquals(200);
+
+    // Check Route only example entry.
+    $this->clickLink(t('Route only example'));
+    $this->clickLink('examples/menu-example/route-only/callback');
+    $this->assertSession()->pageTextContains('The route entry has no corresponding menu links entry');
+
+    // Check links on Tabs landing page.
+    $this->clickLink(t('Tabs'));
+    $this->assertSession()->pageTextContains(t('This is the tab "Default primary tab" in the "basic tabs" example'));
+    $this->assertSession()->linkByHrefExists('/examples/menu-example/tabs');
+    // Check presence of default tabs.
+    $this->assertSession()->linkByHrefExists('/examples/menu-example/tabs/default/second');
+    $this->assertSession()->linkByHrefExists('/examples/menu-example/tabs/default/third');
+
+    // Check second tab.
+    $this->drupalGet('examples/menu-example/tabs/second');
+    $this->assertSession()->pageTextContains(t('This is the tab "Second" in the "basic tabs" example'));
+
+    // Check third tab.
+    $this->clickLink(t('Third'));
+    $this->assertSession()->pageTextContains(t('This is the tab "Third" in the "basic tabs" example'));
+
+    // Now verify 'URL arguments' menu entry to be working with two arguments.
+    $this->clickLink(t('URL Arguments'));
+    $this->drupalGet(Url::fromRoute('examples.menu_example.use_url_arguments', ['arg1' => 'one', 'arg2' => 'two']));
+    $this->assertSession()->pageTextContains(t('Argument 1 = one'));
+    $this->assertSession()->pageTextContains(t('Argument 2 = two'));
+
+    // Check 'placeholder arguments' menu entry.
+    $this->clickLink(t('Placeholder Arguments'));
+    $this->clickLink(t('examples/menu-example/placeholder-argument/3343/display'));
+    $this->assertSession()->pageTextContains('3343');
+
+    // Check altered route example.
+    $this->drupalGet('examples/menu-example/menu-altered-path');
+    $this->assertSession()->pageTextContains('Menu item altered by RouteSubscriber::alterRoutes');
+
+  }
+
+}
