diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/OptionTagHelper.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/OptionTagHelper.cs
new file mode 100644
index 0000000000..b1701904dc
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.TagHelpers/OptionTagHelper.cs
@@ -0,0 +1,99 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using Microsoft.AspNet.Mvc.Rendering;
+using Microsoft.AspNet.Razor.Runtime.TagHelpers;
+using Microsoft.AspNet.Razor.TagHelpers;
+
+namespace Microsoft.AspNet.Mvc.TagHelpers
+{
+ ///
+ /// implementation targeting <option> elements.
+ ///
+ ///
+ /// This works in conjunction with . It has
+ /// in order to read element's content but does not modify that content. The
+ /// only modification it makes is to add a selected attribute in some cases.
+ ///
+ [ContentBehavior(ContentBehavior.Modify)]
+ public class OptionTagHelper : TagHelper
+ {
+ // Protected to ensure subclasses are correctly activated. Internal for ease of use when testing.
+ [Activate]
+ protected internal IHtmlGenerator Generator { get; set; }
+
+ // Protected to ensure subclasses are correctly activated. Internal for ease of use when testing.
+ [Activate]
+ protected internal ViewContext ViewContext { get; set; }
+
+ ///
+ /// Specifies that this <option> is pre-selected.
+ ///
+ ///
+ /// Passed through to the generated HTML in all cases.
+ ///
+ public string Selected { get; set; }
+
+ ///
+ /// Specifies a value for the <option> element.
+ ///
+ ///
+ /// Passed through to the generated HTML in all cases.
+ ///
+ public string Value { get; set; }
+
+ ///
+ ///
+ /// Does nothing unless contains a
+ /// entry and that entry is a non-empty
+ /// instance. Also does nothing if the associated <option> is already
+ /// selected.
+ ///
+ public override void Process(TagHelperContext context, TagHelperOutput output)
+ {
+ // Pass through attributes that are also well-known HTML attributes.
+ if (Value != null)
+ {
+ output.CopyHtmlAttribute(nameof(Value), context);
+ }
+
+ if (Selected != null)
+ {
+ // This will always be selected.
+ output.CopyHtmlAttribute(nameof(Selected), context);
+ }
+ else
+ {
+ // Is this element a child of a element the SelectTagHelper targeted?
+ object formDataEntry;
+ ViewContext.FormContext.FormData.TryGetValue(
+ SelectTagHelper.SelectedValuesFormDataKey,
+ out formDataEntry);
+
+ // ... And did the SelectTagHelper determine any selected values?
+ var selectedValues = formDataEntry as ICollection;
+ if (selectedValues != null && selectedValues.Count != 0)
+ {
+ // Encode all selected values for comparison with element content.
+ var encodedValues = new HashSet(StringComparer.OrdinalIgnoreCase);
+ foreach (var selectedValue in selectedValues)
+ {
+ encodedValues.Add(Generator.Encode(selectedValue));
+ }
+
+ // Select this element if value attribute or content matches a selected value. Callers
+ // encode values as-needed before setting TagHelperOutput.Content. But TagHelperOutput itself
+ // encodes attribute values later, when GenerateStartTag() is called.
+ var text = output.Content;
+ var selected = (Value != null) ? selectedValues.Contains(Value) : encodedValues.Contains(text);
+ if (selected)
+ {
+ output.Attributes.Add("selected", "selected");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/OptionTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/OptionTagHelperTest.cs
new file mode 100644
index 0000000000..a4a13790e5
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/OptionTagHelperTest.cs
@@ -0,0 +1,255 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Mvc.ModelBinding;
+using Microsoft.AspNet.Razor.Runtime.TagHelpers;
+using Xunit;
+
+namespace Microsoft.AspNet.Mvc.TagHelpers
+{
+ public class OptionTagHelperTest
+ {
+ // Original content, selected attribute, value attribute, selected values (to place in FormContext.FormData)
+ // and expected output (concatenation of TagHelperOutput generations).
+ public static TheoryData, string> GeneratesExpectedDataSet
+ {
+ get
+ {
+ return new TheoryData, string>
+ {
+ { null, null, null, null,
+ "" },
+ { null, string.Empty, "value", null,
+ "" },
+ { null, "selected", "value", null,
+ "" },
+ { null, null, "value", new string[0],
+ "" },
+ { null, null, "value", new [] { string.Empty, },
+ "" },
+ { null, string.Empty, "value", new [] { string.Empty, },
+ "" },
+ { null, null, "value", new [] { "value", },
+ "" },
+ { null, null, "value", new [] { string.Empty, "value", },
+ "" },
+
+ { string.Empty, null, null, null,
+ "" },
+ { string.Empty, string.Empty, null, null,
+ "" },
+ { string.Empty, "selected", null, null,
+ "" },
+ { string.Empty, null, null, new string[0],
+ "" },
+ { string.Empty, null, null, new [] { string.Empty, },
+ "" },
+ { string.Empty, string.Empty, null, new [] { string.Empty, },
+ "" },
+ { string.Empty, null, null, new [] { "text", },
+ "" },
+ { string.Empty, null, null, new [] { string.Empty, "text", },
+ "" },
+
+ { "text", null, null, null,
+ "text" },
+ { "text", string.Empty, null, null,
+ "text" },
+ { "text", "selected", null, null,
+ "text" },
+ { "text", null, null, new string[0],
+ "text" },
+ { "text", null, null, new [] { string.Empty, },
+ "text" },
+ { "text", null, null, new [] { "text", },
+ "text" },
+ { "text", string.Empty, null, new [] { "text", },
+ "text" },
+ { "text", null, null, new [] { string.Empty, "text", },
+ "text" },
+
+ { "text", string.Empty, "value", null,
+ "text" },
+ { "text", "selected", "value", null,
+ "text" },
+ { "text", null, "value", new string[0],
+ "text" },
+ { "text", null, "value", new [] { string.Empty, },
+ "text" },
+ { "text", string.Empty, "value", new [] { string.Empty, },
+ "text" },
+ { "text", null, "value", new [] { "text", },
+ "text" },
+ { "text", null, "value", new [] { "value", },
+ "text" },
+ { "text", null, "value", new [] { string.Empty, "value", },
+ "text" },
+ };
+ }
+ }
+
+ // Original content, selected attribute, value attribute, selected values (to place in FormContext.FormData)
+ // and expected output (concatenation of TagHelperOutput generations). Excludes non-null selected attribute,
+ // null selected values, and empty selected values cases.
+ public static IEnumerable