diff --git a/core/lib/Drupal/Core/Render/Element/HtmlTag.php b/core/lib/Drupal/Core/Render/Element/HtmlTag.php
index 0b9ac91e4b..2413784586 100644
--- a/core/lib/Drupal/Core/Render/Element/HtmlTag.php
+++ b/core/lib/Drupal/Core/Render/Element/HtmlTag.php
@@ -41,6 +41,7 @@ class HtmlTag extends RenderElement {
   static protected $voidElements = [
     'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
     'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr',
+    'rect', 'circle', 'polygon', 'ellipse', 'stop', 'use', 'path',
   ];
 
   /**
@@ -59,7 +60,7 @@ public function getInfo() {
   }
 
   /**
-   * Pre-render callback: Renders a generic HTML tag with attributes into #markup.
+   * Pre-render callback: Renders a generic HTML tag with attributes.
    *
    * @param array $element
    *   An associative array containing:
@@ -84,21 +85,27 @@ public static function preRenderHtmlTag($element) {
     // An HTML tag should not contain any special characters. Escape them to
     // ensure this cannot be abused.
     $escaped_tag = HtmlUtility::escape($element['#tag']);
-    $markup = '<' . $escaped_tag . $attributes;
+    $open_tag = '<' . $escaped_tag . $attributes;
+    $close_tag = '</' . $escaped_tag . ">\n";
+    $prefix = isset($element['#prefix']) ? $element['#prefix'] . $open_tag : $open_tag;
+    $suffix = isset($element['#suffix']) ? $close_tag . $element['#suffix'] : $close_tag;
     // Construct a void element.
     if (in_array($element['#tag'], self::$voidElements)) {
-      $markup .= " />\n";
+      $prefix .= " />\n";
+      $suffix = '';
     }
     // Construct all other elements.
     else {
-      $markup .= '>';
-      $markup .= $element['#value'] instanceof MarkupInterface ? $element['#value'] : Xss::filterAdmin($element['#value']);
-      $markup .= '</' . $escaped_tag . ">\n";
+      $prefix .= '>';
+      $markup = $element['#value'] instanceof MarkupInterface ? $element['#value'] : Xss::filterAdmin($element['#value']);
+      $element['#markup'] = Markup::create($markup);
     }
     if (!empty($element['#noscript'])) {
-      $markup = "<noscript>$markup</noscript>";
+      $prefix = '<noscript>' . $prefix;
+      $suffix .= '</noscript>';
     }
-    $element['#markup'] = Markup::create($markup);
+    $element['#prefix'] = Markup::create($prefix);
+    $element['#suffix'] = Markup::create($suffix);
     return $element;
   }
 
diff --git a/core/tests/Drupal/KernelTests/KernelTestBaseTest.php b/core/tests/Drupal/KernelTests/KernelTestBaseTest.php
index 8ec7c5497a..60c2ce31ae 100644
--- a/core/tests/Drupal/KernelTests/KernelTestBaseTest.php
+++ b/core/tests/Drupal/KernelTests/KernelTestBaseTest.php
@@ -182,7 +182,7 @@ public function testRender() {
     $output = \Drupal::service('renderer')->renderRoot($build);
     $this->assertEquals('core', \Drupal::theme()->getActiveTheme()->getName());
 
-    $this->assertEquals($expected, $build['#children']);
+    $this->assertEquals($expected, $build['#markup']);
     $this->assertEquals($expected, $output);
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Render/Element/HtmlTagTest.php b/core/tests/Drupal/Tests/Core/Render/Element/HtmlTagTest.php
index 46dd91a87d..713da2f9c0 100644
--- a/core/tests/Drupal/Tests/Core/Render/Element/HtmlTagTest.php
+++ b/core/tests/Drupal/Tests/Core/Render/Element/HtmlTagTest.php
@@ -3,14 +3,14 @@
 namespace Drupal\Tests\Core\Render\Element;
 
 use Drupal\Core\Render\Markup;
-use Drupal\Tests\UnitTestCase;
+use Drupal\Tests\Core\Render\RendererTestBase;
 use Drupal\Core\Render\Element\HtmlTag;
 
 /**
  * @coversDefaultClass \Drupal\Core\Render\Element\HtmlTag
  * @group Render
  */
-class HtmlTagTest extends UnitTestCase {
+class HtmlTagTest extends RendererTestBase {
 
   /**
    * @covers ::getInfo
@@ -29,8 +29,12 @@ public function testGetInfo() {
    */
   public function testPreRenderHtmlTag($element, $expected) {
     $result = HtmlTag::preRenderHtmlTag($element);
-    $this->assertArrayHasKey('#markup', $result);
-    $this->assertEquals($expected, $result['#markup']);
+    foreach ($result as &$child) {
+      if (is_array($child) && isset($child['#tag'])) {
+        $child = HtmlTag::preRenderHtmlTag($child);
+      }
+    }
+    $this->assertEquals($expected, (string) $this->renderer->renderRoot($result));
   }
 
   /**
@@ -92,6 +96,112 @@ public function providerPreRenderHtmlTag() {
     ];
     $tags[] = [$element, "<p>value</p>\n"];
 
+    // Ensure that nested render arrays render properly.
+    $element = [
+      '#tag' => 'p',
+      '#value' => NULL,
+      [
+        ['#markup' => '<b>value1</b>'],
+        ['#markup' => '<b>value2</b>'],
+      ],
+    ];
+    $tags[] = [$element, "<p><b>value1</b><b>value2</b></p>\n"];
+
+    // Ensure svg elements.
+    $element = [
+      '#tag' => 'rect',
+      '#attributes' => [
+        'width' => 25,
+        'height' => 25,
+        'x' => 5,
+        'y' => 10,
+      ],
+    ];
+    $tags[] = [$element, '<rect width="25" height="25" x="5" y="10" />' . "\n"];
+
+    $element = [
+      '#tag' => 'circle',
+      '#attributes' => [
+        'cx' => 100,
+        'cy' => 100,
+        'r' => 100,
+      ],
+    ];
+    $tags[] = [$element, '<circle cx="100" cy="100" r="100" />' . "\n"];
+
+    $element = [
+      '#tag' => 'polygon',
+      '#attributes' => [
+        'points' => '60,20 100,40 100,80 60,100 20,80 20,40',
+      ],
+    ];
+    $tags[] = [$element, '<polygon points="60,20 100,40 100,80 60,100 20,80 20,40" />' . "\n"];
+
+    $element = [
+      '#tag' => 'ellipse',
+      '#attributes' => [
+        'cx' => 60,
+        'cy' => 60,
+        'rx' => 50,
+        'ry' => 25,
+      ],
+    ];
+    $tags[] = [$element, '<ellipse cx="60" cy="60" rx="50" ry="25" />' . "\n"];
+
+    $element = [
+      '#tag' => 'use',
+      '#attributes' => [
+        'x' => 50,
+        'y' => 10,
+        'width' => 50,
+        'height' => 50,
+      ],
+    ];
+    $tags[] = [$element, '<use x="50" y="10" width="50" height="50" />' . "\n"];
+
+    $element = [
+      '#tag' => 'path',
+      '#attributes' => [
+        'd' => 'M 100 100 L 300 100 L 200 300 z',
+        'fill' => 'orange',
+        'stroke' => 'black',
+        'stroke-width' => 3,
+      ],
+    ];
+    $tags[] = [$element, '<path d="M 100 100 L 300 100 L 200 300 z" fill="orange" stroke="black" stroke-width="3" />' . "\n"];
+
+    $element = [
+      '#tag' => 'stop',
+      '#attributes' => [
+        'offset' => '5%',
+        'stop-color' => '#F60',
+      ],
+    ];
+    $tags[] = [$element, '<stop offset="5%" stop-color="#F60" />' . "\n"];
+
+    // Nested svg elements.
+    $element = [
+      '#tag' => 'linearGradient',
+      '#value' => NULL,
+      [
+        '#tag' => 'stop',
+        '#value' => NULL,
+        '#attributes' => [
+          'offset' => '5%',
+          'stop-color' => '#F60',
+        ],
+      ],
+      [
+        '#tag' => 'stop',
+        '#value' => NULL,
+        '#attributes' => [
+          'offset' => '95%',
+          'stop-color' => '#FF6',
+        ],
+      ],
+    ];
+    $tags[] = [$element, '<linearGradient><stop offset="5%" stop-color="#F60" />' . "\n" . '<stop offset="95%" stop-color="#FF6" />' . "\n" . '</linearGradient>' . "\n"];
+
     return $tags;
   }
 
