Index: src/wp-includes/nav-menu-template.php
===================================================================
--- src/wp-includes/nav-menu-template.php	(revision 48283)
+++ src/wp-includes/nav-menu-template.php	(working copy)
@@ -15,31 +15,33 @@
  *
  * @since 3.0.0
  * @since 4.7.0 Added the `item_spacing` argument.
+ * @since 5.5.0 Added the `container_aria_label` argument.
  *
  * @param array $args {
  *     Optional. Array of nav menu arguments.
  *
- *     @type int|string|WP_Term $menu            Desired menu. Accepts a menu ID, slug, name, or object. Default empty.
- *     @type string             $menu_class      CSS class to use for the ul element which forms the menu. Default 'menu'.
- *     @type string             $menu_id         The ID that is applied to the ul element which forms the menu.
- *                                               Default is the menu slug, incremented.
- *     @type string             $container       Whether to wrap the ul, and what to wrap it with. Default 'div'.
- *     @type string             $container_class Class that is applied to the container. Default 'menu-{menu slug}-container'.
- *     @type string             $container_id    The ID that is applied to the container. Default empty.
- *     @type callable|bool      $fallback_cb     If the menu doesn't exist, a callback function will fire.
- *                                               Default is 'wp_page_menu'. Set to false for no fallback.
- *     @type string             $before          Text before the link markup. Default empty.
- *     @type string             $after           Text after the link markup. Default empty.
- *     @type string             $link_before     Text before the link text. Default empty.
- *     @type string             $link_after      Text after the link text. Default empty.
- *     @type bool               $echo            Whether to echo the menu or return it. Default true.
- *     @type int                $depth           How many levels of the hierarchy are to be included. 0 means all. Default 0.
- *     @type object             $walker          Instance of a custom walker class. Default empty.
- *     @type string             $theme_location  Theme location to be used. Must be registered with register_nav_menu()
- *                                               in order to be selectable by the user.
- *     @type string             $items_wrap      How the list items should be wrapped. Default is a ul with an id and class.
- *                                               Uses printf() format with numbered placeholders.
- *     @type string             $item_spacing    Whether to preserve whitespace within the menu's HTML. Accepts 'preserve' or 'discard'. Default 'preserve'.
+ *     @type int|string|WP_Term $menu                 Desired menu. Accepts a menu ID, slug, name, or object. Default empty.
+ *     @type string             $menu_class           CSS class to use for the ul element which forms the menu. Default 'menu'.
+ *     @type string             $menu_id              The ID that is applied to the ul element which forms the menu.
+ *                                                    Default is the menu slug, incremented.
+ *     @type string             $container            Whether to wrap the ul, and what to wrap it with. Default 'div'.
+ *     @type string             $container_class      Class that is applied to the container. Default 'menu-{menu slug}-container'.
+ *     @type string             $container_id         The ID that is applied to the container. Default empty.
+ *     @type string             $container_aria_label The aria-label attribute that is applied to the container when it's a nav element. Default empty.
+ *     @type callable|bool      $fallback_cb          If the menu doesn't exist, a callback function will fire.
+ *                                                    Default is 'wp_page_menu'. Set to false for no fallback.
+ *     @type string             $before               Text before the link markup. Default empty.
+ *     @type string             $after                Text after the link markup. Default empty.
+ *     @type string             $link_before          Text before the link text. Default empty.
+ *     @type string             $link_after           Text after the link text. Default empty.
+ *     @type bool               $echo                 Whether to echo the menu or return it. Default true.
+ *     @type int                $depth                How many levels of the hierarchy are to be included. 0 means all. Default 0.
+ *     @type object             $walker               Instance of a custom walker class. Default empty.
+ *     @type string             $theme_location       Theme location to be used. Must be registered with register_nav_menu()
+ *                                                    in order to be selectable by the user.
+ *     @type string             $items_wrap           How the list items should be wrapped. Default is a ul with an id and class.
+ *                                                    Uses printf() format with numbered placeholders.
+ *     @type string             $item_spacing         Whether to preserve whitespace within the menu's HTML. Accepts 'preserve' or 'discard'. Default 'preserve'.
  * }
  * @return void|string|false Void if 'echo' argument is true, menu output if 'echo' is false.
  *                           False if there are no items or no menu was found.
@@ -48,23 +50,24 @@
 	static $menu_id_slugs = array();
 
 	$defaults = array(
-		'menu'            => '',
-		'container'       => 'div',
-		'container_class' => '',
-		'container_id'    => '',
-		'menu_class'      => 'menu',
-		'menu_id'         => '',
-		'echo'            => true,
-		'fallback_cb'     => 'wp_page_menu',
-		'before'          => '',
-		'after'           => '',
-		'link_before'     => '',
-		'link_after'      => '',
-		'items_wrap'      => '<ul id="%1$s" class="%2$s">%3$s</ul>',
-		'item_spacing'    => 'preserve',
-		'depth'           => 0,
-		'walker'          => '',
-		'theme_location'  => '',
+		'menu'                 => '',
+		'container'            => 'div',
+		'container_class'      => '',
+		'container_id'         => '',
+		'container_aria_label' => '',
+		'menu_class'           => 'menu',
+		'menu_id'              => '',
+		'echo'                 => true,
+		'fallback_cb'          => 'wp_page_menu',
+		'before'               => '',
+		'after'                => '',
+		'link_before'          => '',
+		'link_after'           => '',
+		'items_wrap'           => '<ul id="%1$s" class="%2$s">%3$s</ul>',
+		'item_spacing'         => 'preserve',
+		'depth'                => 0,
+		'walker'               => '',
+		'theme_location'       => '',
 	);
 
 	$args = wp_parse_args( $args, $defaults );
@@ -176,7 +179,8 @@
 			$show_container = true;
 			$class          = $args->container_class ? ' class="' . esc_attr( $args->container_class ) . '"' : ' class="menu-' . $menu->slug . '-container"';
 			$id             = $args->container_id ? ' id="' . esc_attr( $args->container_id ) . '"' : '';
-			$nav_menu      .= '<' . $args->container . $id . $class . '>';
+			$aria_label     = ( 'nav' === $args->container && $args->container_aria_label ) ? ' aria-label="' . esc_attr( $args->container_aria_label ) . '"' : '';
+			$nav_menu      .= '<' . $args->container . $id . $class . $aria_label . '>';
 		}
 	}
 
Index: src/wp-includes/widgets/class-wp-nav-menu-widget.php
===================================================================
--- src/wp-includes/widgets/class-wp-nav-menu-widget.php	(revision 48283)
+++ src/wp-includes/widgets/class-wp-nav-menu-widget.php	(working copy)
@@ -46,7 +46,8 @@
 			return;
 		}
 
-		$title = ! empty( $instance['title'] ) ? $instance['title'] : '';
+		$default_title = __( 'Menu' );
+		$title         = ! empty( $instance['title'] ) ? $instance['title'] : '';
 
 		/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
 		$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
@@ -57,12 +58,38 @@
 			echo $args['before_title'] . $title . $args['after_title'];
 		}
 
-		$nav_menu_args = array(
-			'fallback_cb' => '',
-			'menu'        => $nav_menu,
-		);
+		$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
 
 		/**
+		 * Filters the HTML format of widgets with navigation links.
+		 *
+		 * @since 5.5.0
+		 *
+		 * @param string $format The type of markup to use in widgets with navigation links.
+		 *                       Accepts 'html5', 'xhtml'.
+		 */
+		$format = apply_filters( 'navigation_widgets_format', $format );
+
+		if ( 'html5' === $format ) {
+			// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
+			$title      = trim( strip_tags( $title ) );
+			$aria_label = $title ? $title : $default_title;
+
+			$nav_menu_args = array(
+				'fallback_cb'          => '',
+				'menu'                 => $nav_menu,
+				'container'            => 'nav',
+				'container_aria_label' => $aria_label,
+				'items_wrap'           => '<ul id="%1$s" class="%2$s">%3$s</ul>',
+			);
+		} else {
+			$nav_menu_args = array(
+				'fallback_cb' => '',
+				'menu'        => $nav_menu,
+			);
+		}
+
+		/**
 		 * Filters the arguments for the Navigation Menu widget.
 		 *
 		 * @since 4.2.0
Index: src/wp-includes/widgets/class-wp-widget-archives.php
===================================================================
--- src/wp-includes/widgets/class-wp-widget-archives.php	(revision 48283)
+++ src/wp-includes/widgets/class-wp-widget-archives.php	(working copy)
@@ -40,7 +40,8 @@
 	 * @param array $instance Settings for the current Archives widget instance.
 	 */
 	public function widget( $args, $instance ) {
-		$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Archives' );
+		$default_title = __( 'Archives' );
+		$title         = ! empty( $instance['title'] ) ? $instance['title'] : $default_title;
 
 		/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
 		$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
@@ -120,37 +121,60 @@
 })();
 /* ]]> */
 </script>
+			<?php
+		} else {
+			$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
 
-		<?php } else { ?>
-		<ul>
-			<?php
-			wp_get_archives(
-				/**
-				 * Filters the arguments for the Archives widget.
-				 *
-				 * @since 2.8.0
-				 * @since 4.9.0 Added the `$instance` parameter.
-				 *
-				 * @see wp_get_archives()
-				 *
-				 * @param array $args     An array of Archives option arguments.
-				 * @param array $instance Array of settings for the current widget.
-				 */
-				apply_filters(
-					'widget_archives_args',
-					array(
-						'type'            => 'monthly',
-						'show_post_count' => $count,
-					),
-					$instance
-				)
-			);
+			/**
+			 * Filters the HTML format of widgets with navigation links.
+			 *
+			 * @since 5.5.0
+			 *
+			 * @param string $format The type of markup to use in widgets with navigation links.
+			 *                       Accepts 'html5', 'xhtml'.
+			 */
+			$format = apply_filters( 'navigation_widgets_format', $format );
+
+			if ( 'html5' === $format ) {
+				// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
+				$title      = trim( strip_tags( $title ) );
+				$aria_label = $title ? $title : $default_title;
+				echo '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
+			}
 			?>
-		</ul>
+
+			<ul>
+				<?php
+				wp_get_archives(
+					/**
+					 * Filters the arguments for the Archives widget.
+					 *
+					 * @since 2.8.0
+					 * @since 4.9.0 Added the `$instance` parameter.
+					 *
+					 * @see wp_get_archives()
+					 *
+					 * @param array $args     An array of Archives option arguments.
+					 * @param array $instance Array of settings for the current widget.
+					 */
+					apply_filters(
+						'widget_archives_args',
+						array(
+							'type'            => 'monthly',
+							'show_post_count' => $count,
+						),
+						$instance
+					)
+				);
+				?>
+			</ul>
+			<?php if ( 'html5' === $format ) : ?>
+				</nav>
+			<?php endif; ?>
+
 			<?php
+			echo $args['after_widget'];
 		}
-
-		echo $args['after_widget'];
 	}
 
 	/**
Index: src/wp-includes/widgets/class-wp-widget-categories.php
===================================================================
--- src/wp-includes/widgets/class-wp-widget-categories.php	(revision 48283)
+++ src/wp-includes/widgets/class-wp-widget-categories.php	(working copy)
@@ -44,7 +44,8 @@
 	public function widget( $args, $instance ) {
 		static $first_dropdown = true;
 
-		$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Categories' );
+		$default_title = __( 'Categories' );
+		$title         = ! empty( $instance['title'] ) ? $instance['title'] : $default_title;
 
 		/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
 		$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
@@ -109,23 +110,47 @@
 
 			<?php
 		} else {
-			?>
-		<ul>
-			<?php
-			$cat_args['title_li'] = '';
+			$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
 
 			/**
-			 * Filters the arguments for the Categories widget.
+			 * Filters the HTML format of widgets with navigation links.
 			 *
-			 * @since 2.8.0
-			 * @since 4.9.0 Added the `$instance` parameter.
+			 * @since 5.5.0
 			 *
-			 * @param array $cat_args An array of Categories widget options.
-			 * @param array $instance Array of settings for the current widget.
+			 * @param string $format The type of markup to use in widgets with navigation links.
+			 *                       Accepts 'html5', 'xhtml'.
 			 */
-			wp_list_categories( apply_filters( 'widget_categories_args', $cat_args, $instance ) );
+			$format = apply_filters( 'navigation_widgets_format', $format );
+
+			if ( 'html5' === $format ) {
+				// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
+				$title      = trim( strip_tags( $title ) );
+				$aria_label = $title ? $title : $default_title;
+				echo '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
+			}
 			?>
-		</ul>
+
+			<ul>
+				<?php
+				$cat_args['title_li'] = '';
+
+				/**
+				 * Filters the arguments for the Categories widget.
+				 *
+				 * @since 2.8.0
+				 * @since 4.9.0 Added the `$instance` parameter.
+				 *
+				 * @param array $cat_args An array of Categories widget options.
+				 * @param array $instance Array of settings for the current widget.
+				 */
+				wp_list_categories( apply_filters( 'widget_categories_args', $cat_args, $instance ) );
+				?>
+			</ul>
+
+			<?php if ( 'html5' === $format ) : ?>
+				</nav>
+			<?php endif; ?>
+
 			<?php
 		}
 
Index: src/wp-includes/widgets/class-wp-widget-meta.php
===================================================================
--- src/wp-includes/widgets/class-wp-widget-meta.php	(revision 48283)
+++ src/wp-includes/widgets/class-wp-widget-meta.php	(working copy)
@@ -42,7 +42,8 @@
 	 * @param array $instance Settings for the current Meta widget instance.
 	 */
 	public function widget( $args, $instance ) {
-		$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Meta' );
+		$default_title = __( 'Meta' );
+		$title         = ! empty( $instance['title'] ) ? $instance['title'] : $default_title;
 
 		/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
 		$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
@@ -52,12 +53,34 @@
 		if ( $title ) {
 			echo $args['before_title'] . $title . $args['after_title'];
 		}
+
+		$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
+
+		/**
+		 * Filters the HTML format of widgets with navigation links.
+		 *
+		 * @since 5.5.0
+		 *
+		 * @param string $format The type of markup to use in widgets with navigation links.
+		 *                       Accepts 'html5', 'xhtml'.
+		 */
+		$format = apply_filters( 'navigation_widgets_format', $format );
+
+		if ( 'html5' === $format ) {
+			// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
+			$title      = trim( strip_tags( $title ) );
+			$aria_label = $title ? $title : $default_title;
+			echo '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
+		}
 		?>
-			<ul>
+
+
+		<ul>
 			<?php wp_register(); ?>
 			<li><?php wp_loginout(); ?></li>
 			<li><a href="<?php echo esc_url( get_bloginfo( 'rss2_url' ) ); ?>"><?php _e( 'Entries feed' ); ?></a></li>
 			<li><a href="<?php echo esc_url( get_bloginfo( 'comments_rss2_url' ) ); ?>"><?php _e( 'Comments feed' ); ?></a></li>
+
 			<?php
 			/**
 			 * Filters the "WordPress.org" list item HTML in the Meta widget.
@@ -80,10 +103,15 @@
 
 			wp_meta();
 			?>
-			</ul>
-			<?php
 
-			echo $args['after_widget'];
+		</ul>
+
+		<?php if ( 'html5' === $format ) : ?>
+			</nav>
+		<?php endif; ?>
+
+		<?php
+		echo $args['after_widget'];
 	}
 
 	/**
Index: src/wp-includes/widgets/class-wp-widget-pages.php
===================================================================
--- src/wp-includes/widgets/class-wp-widget-pages.php	(revision 48283)
+++ src/wp-includes/widgets/class-wp-widget-pages.php	(working copy)
@@ -40,7 +40,8 @@
 	 * @param array $instance Settings for the current Pages widget instance.
 	 */
 	public function widget( $args, $instance ) {
-		$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Pages' );
+		$default_title = __( 'Pages' );
+		$title         = ! empty( $instance['title'] ) ? $instance['title'] : $default_title;
 
 		/**
 		 * Filters the widget title.
@@ -89,10 +90,35 @@
 			if ( $title ) {
 				echo $args['before_title'] . $title . $args['after_title'];
 			}
+
+			$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
+
+			/**
+			 * Filters the HTML format of widgets with navigation links.
+			 *
+			 * @since 5.5.0
+			 *
+			 * @param string $format The type of markup to use in widgets with navigation links.
+			 *                       Accepts 'html5', 'xhtml'.
+			 */
+			$format = apply_filters( 'navigation_widgets_format', $format );
+
+			if ( 'html5' === $format ) {
+				// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
+				$title      = trim( strip_tags( $title ) );
+				$aria_label = $title ? $title : $default_title;
+				echo '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
+			}
 			?>
-		<ul>
-			<?php echo $out; ?>
-		</ul>
+
+			<ul>
+				<?php echo $out; ?>
+			</ul>
+
+			<?php if ( 'html5' === $format ) : ?>
+				</nav>
+			<?php endif; ?>
+
 			<?php
 			echo $args['after_widget'];
 		}
Index: src/wp-includes/widgets/class-wp-widget-recent-comments.php
===================================================================
--- src/wp-includes/widgets/class-wp-widget-recent-comments.php	(revision 48283)
+++ src/wp-includes/widgets/class-wp-widget-recent-comments.php	(working copy)
@@ -82,7 +82,8 @@
 
 		$output = '';
 
-		$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'Recent Comments' );
+		$default_title = __( 'Recent Comments' );
+		$title         = ( ! empty( $instance['title'] ) ) ? $instance['title'] : $default_title;
 
 		/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
 		$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
@@ -123,6 +124,25 @@
 		$recent_comments_id = ( $first_instance ) ? 'recentcomments' : "recentcomments-{$this->number}";
 		$first_instance     = false;
 
+		$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
+
+		/**
+		 * Filters the HTML format of widgets with navigation links.
+		 *
+		 * @since 5.5.0
+		 *
+		 * @param string $format The type of markup to use in widgets with navigation links.
+		 *                       Accepts 'html5', 'xhtml'.
+		 */
+		$format = apply_filters( 'navigation_widgets_format', $format );
+
+		if ( 'html5' === $format ) {
+			// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
+			$title      = trim( strip_tags( $title ) );
+			$aria_label = $title ? $title : $default_title;
+			$output    .= '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
+		}
+
 		$output .= '<ul id="' . esc_attr( $recent_comments_id ) . '">';
 		if ( is_array( $comments ) && $comments ) {
 			// Prime cache for associated posts. (Prime post term cache if we need it for permalinks.)
@@ -141,6 +161,11 @@
 			}
 		}
 		$output .= '</ul>';
+
+		if ( 'html5' === $format ) {
+			$output .= '</nav>';
+		}
+
 		$output .= $args['after_widget'];
 
 		echo $output;
Index: src/wp-includes/widgets/class-wp-widget-recent-posts.php
===================================================================
--- src/wp-includes/widgets/class-wp-widget-recent-posts.php	(revision 48283)
+++ src/wp-includes/widgets/class-wp-widget-recent-posts.php	(working copy)
@@ -45,7 +45,8 @@
 			$args['widget_id'] = $this->id;
 		}
 
-		$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'Recent Posts' );
+		$default_title = __( 'Recent Posts' );
+		$title         = ( ! empty( $instance['title'] ) ) ? $instance['title'] : $default_title;
 
 		/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
 		$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
@@ -84,12 +85,34 @@
 			return;
 		}
 		?>
+
 		<?php echo $args['before_widget']; ?>
+
 		<?php
 		if ( $title ) {
 			echo $args['before_title'] . $title . $args['after_title'];
 		}
+
+		$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
+
+		/**
+		 * Filters the HTML format of widgets with navigation links.
+		 *
+		 * @since 5.5.0
+		 *
+		 * @param string $format The type of markup to use in widgets with navigation links.
+		 *                       Accepts 'html5', 'xhtml'.
+		 */
+		$format = apply_filters( 'navigation_widgets_format', $format );
+
+		if ( 'html5' === $format ) {
+			// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
+			$title      = trim( strip_tags( $title ) );
+			$aria_label = $title ? $title : $default_title;
+			echo '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
+		}
 		?>
+
 		<ul>
 			<?php foreach ( $r->posts as $recent_post ) : ?>
 				<?php
@@ -109,6 +132,10 @@
 				</li>
 			<?php endforeach; ?>
 		</ul>
+		<?php if ( 'html5' === $format ) : ?>
+			</nav>
+		<?php endif; ?>
+
 		<?php
 		echo $args['after_widget'];
 	}
Index: src/wp-includes/widgets/class-wp-widget-rss.php
===================================================================
--- src/wp-includes/widgets/class-wp-widget-rss.php	(revision 48283)
+++ src/wp-includes/widgets/class-wp-widget-rss.php	(working copy)
@@ -94,7 +94,32 @@
 		if ( $title ) {
 			echo $args['before_title'] . $title . $args['after_title'];
 		}
+
+		$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
+
+		/**
+		 * Filters the HTML format of widgets with navigation links.
+		 *
+		 * @since 5.5.0
+		 *
+		 * @param string $format The type of markup to use in widgets with navigation links.
+		 *                       Accepts 'html5', 'xhtml'.
+		 */
+		$format = apply_filters( 'navigation_widgets_format', $format );
+
+		if ( 'html5' === $format ) {
+			// The title may be filtered: Strip out HTML and make sure the aria-label is never empty.
+			$title      = trim( strip_tags( $title ) );
+			$aria_label = $title ? $title : __( 'RSS Feed' );
+			echo '<nav role="navigation" aria-label="' . esc_attr( $aria_label ) . '">';
+		}
+
 		wp_widget_rss_output( $rss, $instance );
+
+		if ( 'html5' === $format ) {
+			echo '</nav>';
+		}
+
 		echo $args['after_widget'];
 
 		if ( ! is_wp_error( $rss ) ) {
