diff --git a/core/lib/Drupal/Component/Utility/HtmlAttributeValueOutput.php b/core/lib/Drupal/Component/Utility/HtmlAttributeValueOutput.php
new file mode 100644
index 0000000..a05e60d
--- /dev/null
+++ b/core/lib/Drupal/Component/Utility/HtmlAttributeValueOutput.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\Component\Utility\PlainTextOutput.
+ */
+
+namespace Drupal\Component\Utility;
+
+/**
+ * Implements an output strategy to be used to format strings to be used as
+ * HTML attribute values.
+ */
+class HtmlAttributeValueOutput implements OutputStrategyInterface {
+
+  /**
+   * Given an HTML string, translate it to a plain text string and escape.
+   *
+   * @param $string|\Drupal\Component\Utility\SafeStringInterface
+   *   An HTML string or a any object that can be cast to string.
+   *
+   * @return string
+   *   A string with HTML tags stripped and HTML entities decoded, and then
+   *   escaped for use within HTML attributes.
+   */
+  public static function renderFromHtml($string) {
+     return Html::escape(PlainTextOutput::renderFromHtml($string));
+  }
+
+}
diff --git a/core/lib/Drupal/Component/Utility/OutputStrategyInterface.php b/core/lib/Drupal/Component/Utility/OutputStrategyInterface.php
new file mode 100644
index 0000000..e968fa2
--- /dev/null
+++ b/core/lib/Drupal/Component/Utility/OutputStrategyInterface.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\Component\Utility\OutputStrategyInterface.
+ */
+
+namespace Drupal\Component\Utility;
+
+/**
+ * Common interface for output strategies.
+ */
+interface OutputStrategyInterface {
+
+  /**
+   * Given an HTML string, translate it to the desired output string.
+   *
+   * @param $string|\Drupal\Component\Utility\SafeStringInterface
+   *   An HTML string.
+   *
+   * @return string
+   *   A new string depending on strategy.
+   */
+  public static function renderFromHtml($string);
+
+}
diff --git a/core/lib/Drupal/Component/Utility/PlainTextOutput.php b/core/lib/Drupal/Component/Utility/PlainTextOutput.php
new file mode 100644
index 0000000..f91240e
--- /dev/null
+++ b/core/lib/Drupal/Component/Utility/PlainTextOutput.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\Component\Utility\PlainTextOutput.
+ */
+
+namespace Drupal\Component\Utility;
+
+/**
+ * Implements an output strategy to be used to format strings as plain text.
+ */
+class PlainTextOutput implements OutputStrategyInterface {
+
+  /**
+   * Given an HTML string, translate it to a plain text string.
+   *
+   * @param $string|\Drupal\Component\Utility\SafeStringInterface
+   *   An HTML string or a any object that can be cast to string.
+   *
+   * @return string
+   *   A string with HTML tags stripped and HTML entities decoded suitable for
+   *   email or other non-HTML context.
+   */
+  public static function renderFromHtml($string) {
+    return Html::decodeEntities(strip_tags((string) $string));
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Component/Utility/HtmlAttributeValueOutputTest.php b/core/tests/Drupal/Tests/Component/Utility/HtmlAttributeValueOutputTest.php
new file mode 100644
index 0000000..51c86f8
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/Utility/HtmlAttributeValueOutputTest.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\Utility\HtmlAttributeValueOutputTest.
+ */
+
+namespace Drupal\Tests\Component\Utility;
+
+use Drupal\Component\Utility\HtmlAttributeValueOutput;
+use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Render\SafeString;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Component\Utility\HtmlAttributeValueOutput
+ * @group Utility
+ */
+class HtmlAttributeValueOutputTest extends UnitTestCase {
+
+  /**
+   * Tests ::renderFromHtml().
+   *
+   * @param $expected
+   *   The expected formatted value.
+   * @param $string
+   *   A string to be formatted.
+   * @param array $args
+   *   (optional) An associative array of replacements to make. Defaults to
+   *   none.
+   *
+   * @covers ::renderFromHtml
+   * @dataProvider providerRenderFromHtml
+   */
+  public function testRenderFromHtml($expected, $string, $args = []) {
+    $markup = SafeMarkup::format($string, $args);
+    $output = HtmlAttributeValueOutput::renderFromHtml($markup);
+    $this->assertSame($expected, $output);
+  }
+
+  /**
+   * Data provider for ::testRenderFromHtml()
+   */
+  public function providerRenderFromHtml() {
+    $data = [];
+
+    $data['simple-text'] = ['Giraffes and wombats', 'Giraffes and wombats'];
+    $data['simple-html'] = ['Giraffes and wombats', '<a href="/muh">Giraffes</a> and <strong>wombats</strong>'];
+    $data['html-with-quote'] = ['Giraffes and quote&quot;s', '<a href="/muh">Giraffes</a> and <strong>quote"s</strong>'];
+
+    $expected = 'The &lt;em&gt; tag makes your text look like &quot;this&quot;.';
+    $string = 'The &lt;em&gt; tag makes your text look like <em>"this"</em>.';
+    $data['escaped-html-with-quotes'] = [$expected, $string];
+    $data['escaped-html-with-quotes-and-placeholders'] = [$expected, 'The @tag tag makes your text look like @result.', ['@tag' =>'<em>', '@result' => SafeString::create('<em>"this"</em>')]];
+
+    $safe_string = $this->getMock('\Drupal\Component\Utility\SafeStringInterface');
+    $safe_string->expects($this->any())
+      ->method('__toString')
+      ->willReturn($string);
+
+    $data['safe-string'] = [$expected, $safe_string];
+
+    return $data;
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Component/Utility/PlainTextOutputTest.php b/core/tests/Drupal/Tests/Component/Utility/PlainTextOutputTest.php
new file mode 100644
index 0000000..a44655d
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/Utility/PlainTextOutputTest.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\Utility\PlainTextOutputTest.
+ */
+
+namespace Drupal\Tests\Component\Utility;
+
+use Drupal\Component\Utility\PlainTextOutput;
+use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Render\SafeString;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Component\Utility\PlainTextOutput
+ * @group Utility
+ */
+class PlainTextOutputTest extends UnitTestCase {
+
+  /**
+   * Tests ::renderFromHtml().
+   *
+   * @param $expected
+   *   The expected formatted value.
+   * @param $string
+   *   A string to be formatted.
+   * @param array $args
+   *   (optional) An associative array of replacements to make. Defaults to
+   *   none.
+   *
+   * @covers ::renderFromHtml
+   * @dataProvider providerRenderFromHtml
+   */
+  public function testRenderFromHtml($expected, $string, $args = []) {
+    $markup = SafeMarkup::format($string, $args);
+    $output = PlainTextOutput::renderFromHtml($markup);
+    $this->assertSame($expected, $output);
+  }
+
+  /**
+   * Data provider for ::testRenderFromHtml()
+   */
+  public function providerRenderFromHtml() {
+    $data = [];
+
+    $data['simple-text'] = ['Giraffes and wombats', 'Giraffes and wombats'];
+    $data['simple-html'] = ['Giraffes and wombats', '<a href="/muh">Giraffes</a> and <strong>wombats</strong>'];
+    $data['html-with-quote'] = ['Giraffes and quote"s', '<a href="/muh">Giraffes</a> and <strong>quote"s</strong>'];
+
+    $expected = 'The <em> tag makes your text look like "this".';
+    $string = 'The &lt;em&gt; tag makes your text look like <em>"this"</em>.';
+    $data['escaped-html-with-quotes'] = [$expected, $string];
+    $data['escaped-html-with-quotes-and-placeholders'] = [$expected, 'The @tag tag makes your text look like @result.', ['@tag' =>'<em>', '@result' => SafeString::create('<em>"this"</em>')]];
+
+    $safe_string = $this->getMock('\Drupal\Component\Utility\SafeStringInterface');
+    $safe_string->expects($this->any())
+      ->method('__toString')
+      ->willReturn($string);
+
+    $data['safe-string'] = [$expected, $safe_string];
+
+    return $data;
+  }
+
+}
