diff --git a/src/Spectre.Console.Tests/Expectations/PromptTests.Should_Auto_Complete_To_Best_Match.verified.txt b/src/Spectre.Console.Tests/Expectations/PromptTests.Should_Auto_Complete_To_Best_Match.verified.txt
new file mode 100644
index 0000000..4986b8a
--- /dev/null
+++ b/src/Spectre.Console.Tests/Expectations/PromptTests.Should_Auto_Complete_To_Best_Match.verified.txt
@@ -0,0 +1 @@
+Favorite fruit? [Banana/Bandana/Orange]: Band    Bandana
diff --git a/src/Spectre.Console.Tests/Expectations/PromptTests.Should_Auto_Complete_To_First_Choice_If_Pressing_Tab_On_Empty_String.verified.txt b/src/Spectre.Console.Tests/Expectations/PromptTests.Should_Auto_Complete_To_First_Choice_If_Pressing_Tab_On_Empty_String.verified.txt
new file mode 100644
index 0000000..675f10f
--- /dev/null
+++ b/src/Spectre.Console.Tests/Expectations/PromptTests.Should_Auto_Complete_To_First_Choice_If_Pressing_Tab_On_Empty_String.verified.txt
@@ -0,0 +1 @@
+Favorite fruit? [Banana/Orange] (Banana): Banana
diff --git a/src/Spectre.Console.Tests/Expectations/PromptTests.Should_Auto_Complete_To_Next_Choice_When_Pressing_Tab_On_A_Match.verified.txt b/src/Spectre.Console.Tests/Expectations/PromptTests.Should_Auto_Complete_To_Next_Choice_When_Pressing_Tab_On_A_Match.verified.txt
new file mode 100644
index 0000000..39f152e
--- /dev/null
+++ b/src/Spectre.Console.Tests/Expectations/PromptTests.Should_Auto_Complete_To_Next_Choice_When_Pressing_Tab_On_A_Match.verified.txt
@@ -0,0 +1 @@
+Favorite fruit? [Apple/Banana/Orange]: Apple     Banana
diff --git a/src/Spectre.Console.Tests/Tools/TestableConsoleInput.cs b/src/Spectre.Console.Tests/Tools/TestableConsoleInput.cs
index cd16bdd..0764be4 100644
--- a/src/Spectre.Console.Tests/Tools/TestableConsoleInput.cs
+++ b/src/Spectre.Console.Tests/Tools/TestableConsoleInput.cs
@@ -23,7 +23,11 @@ namespace Spectre.Console.Tests
             {
                 PushCharacter(character);
             }
+        }
 
+        public void PushTextWithEnter(string input)
+        {
+            PushText(input);
             PushKey(ConsoleKey.Enter);
         }
 
diff --git a/src/Spectre.Console.Tests/Unit/PanelTests.cs b/src/Spectre.Console.Tests/Unit/PanelTests.cs
index ef89490..361f9a9 100644
--- a/src/Spectre.Console.Tests/Unit/PanelTests.cs
+++ b/src/Spectre.Console.Tests/Unit/PanelTests.cs
@@ -1,7 +1,5 @@
 using System.Collections.Generic;
-using System.Text;
 using System.Threading.Tasks;
-using Shouldly;
 using Spectre.Console.Rendering;
 using VerifyXunit;
 using Xunit;
diff --git a/src/Spectre.Console.Tests/Unit/PromptTests.cs b/src/Spectre.Console.Tests/Unit/PromptTests.cs
index 4a5ec8f..acf1790 100644
--- a/src/Spectre.Console.Tests/Unit/PromptTests.cs
+++ b/src/Spectre.Console.Tests/Unit/PromptTests.cs
@@ -13,8 +13,8 @@ namespace Spectre.Console.Tests.Unit
         {
             // Given
             var console = new PlainConsole();
-            console.Input.PushText("ninety-nine");
-            console.Input.PushText("99");
+            console.Input.PushTextWithEnter("ninety-nine");
+            console.Input.PushTextWithEnter("99");
 
             // When
             console.Prompt(new TextPrompt<int>("Age?"));
@@ -46,8 +46,8 @@ namespace Spectre.Console.Tests.Unit
         {
             // Given
             var console = new PlainConsole();
-            console.Input.PushText("Apple");
-            console.Input.PushText("Banana");
+            console.Input.PushTextWithEnter("Apple");
+            console.Input.PushTextWithEnter("Banana");
 
             // When
             console.Prompt(
@@ -65,7 +65,7 @@ namespace Spectre.Console.Tests.Unit
         {
             // Given
             var console = new PlainConsole();
-            console.Input.PushText("Orange");
+            console.Input.PushTextWithEnter("Orange");
 
             // When
             console.Prompt(
@@ -78,15 +78,74 @@ namespace Spectre.Console.Tests.Unit
             return Verifier.Verify(console.Output);
         }
 
+        [Fact]
+        public Task Should_Auto_Complete_To_First_Choice_If_Pressing_Tab_On_Empty_String()
+        {
+            // Given
+            var console = new PlainConsole();
+            console.Input.PushKey(ConsoleKey.Tab);
+            console.Input.PushKey(ConsoleKey.Enter);
+
+            // When
+            console.Prompt(
+                new TextPrompt<string>("Favorite fruit?")
+                    .AddChoice("Banana")
+                    .AddChoice("Orange")
+                    .DefaultValue("Banana"));
+
+            // Then
+            return Verifier.Verify(console.Output);
+        }
+
+        [Fact]
+        public Task Should_Auto_Complete_To_Best_Match()
+        {
+            // Given
+            var console = new PlainConsole();
+            console.Input.PushText("Band");
+            console.Input.PushKey(ConsoleKey.Tab);
+            console.Input.PushKey(ConsoleKey.Enter);
+
+            // When
+            console.Prompt(
+                new TextPrompt<string>("Favorite fruit?")
+                    .AddChoice("Banana")
+                    .AddChoice("Bandana")
+                    .AddChoice("Orange"));
+
+            // Then
+            return Verifier.Verify(console.Output);
+        }
+
+        [Fact]
+        public Task Should_Auto_Complete_To_Next_Choice_When_Pressing_Tab_On_A_Match()
+        {
+            // Given
+            var console = new PlainConsole();
+            console.Input.PushText("Apple");
+            console.Input.PushKey(ConsoleKey.Tab);
+            console.Input.PushKey(ConsoleKey.Enter);
+
+            // When
+            console.Prompt(
+                new TextPrompt<string>("Favorite fruit?")
+                    .AddChoice("Apple")
+                    .AddChoice("Banana")
+                    .AddChoice("Orange"));
+
+            // Then
+            return Verifier.Verify(console.Output);
+        }
+
         [Fact]
         public Task Should_Return_Error_If_Custom_Validation_Fails()
         {
             // Given
             var console = new PlainConsole();
-            console.Input.PushText("22");
-            console.Input.PushText("102");
-            console.Input.PushText("ABC");
-            console.Input.PushText("99");
+            console.Input.PushTextWithEnter("22");
+            console.Input.PushTextWithEnter("102");
+            console.Input.PushTextWithEnter("ABC");
+            console.Input.PushTextWithEnter("99");
 
             // When
             console.Prompt(
diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs
index d83e367..19ef45e 100644
--- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs
+++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs
@@ -1,4 +1,7 @@
 using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
 
 namespace Spectre.Console
 {
@@ -7,7 +10,7 @@ namespace Spectre.Console
     /// </summary>
     public static partial class AnsiConsoleExtensions
     {
-        internal static string ReadLine(this IAnsiConsole console, Style? style, bool secret)
+        internal static string ReadLine(this IAnsiConsole console, Style? style, bool secret, IEnumerable<string>? items = null)
         {
             if (console is null)
             {
@@ -15,35 +18,83 @@ namespace Spectre.Console
             }
 
             style ??= Style.Plain;
+            var text = string.Empty;
+
+            var autocomplete = new List<string>(items ?? Enumerable.Empty<string>());
 
-            var result = string.Empty;
             while (true)
             {
                 var key = console.Input.ReadKey(true);
 
                 if (key.Key == ConsoleKey.Enter)
                 {
-                    return result;
+                    return text;
+                }
+
+                if (key.Key == ConsoleKey.Tab && autocomplete.Count > 0)
+                {
+                    var replace = AutoComplete(autocomplete, text);
+                    if (!string.IsNullOrEmpty(replace))
+                    {
+                        // Render the suggestion
+                        console.Write("\b \b".Repeat(text.Length), style);
+                        console.Write(replace);
+                        text = replace;
+                        continue;
+                    }
                 }
 
                 if (key.Key == ConsoleKey.Backspace)
                 {
-                    if (result.Length > 0)
+                    if (text.Length > 0)
                     {
-                        result = result.Substring(0, result.Length - 1);
+                        text = text.Substring(0, text.Length - 1);
                         console.Write("\b \b");
                     }
 
                     continue;
                 }
 
-                result += key.KeyChar.ToString();
-
                 if (!char.IsControl(key.KeyChar))
                 {
+                    text += key.KeyChar.ToString();
                     console.Write(secret ? "*" : key.KeyChar.ToString(), style);
                 }
             }
         }
+
+        private static string AutoComplete(List<string> autocomplete, string text)
+        {
+            var found = autocomplete.Find(i => i == text);
+            var replace = string.Empty;
+
+            if (found == null)
+            {
+                // Get the closest match
+                var next = autocomplete.Find(i => i.StartsWith(text, true, CultureInfo.InvariantCulture));
+                if (next != null)
+                {
+                    replace = next;
+                }
+                else if (string.IsNullOrEmpty(text))
+                {
+                    // Use the first item
+                    replace = autocomplete[0];
+                }
+            }
+            else
+            {
+                // Get the next match
+                var index = autocomplete.IndexOf(found) + 1;
+                if (index >= autocomplete.Count)
+                {
+                    index = 0;
+                }
+
+                replace = autocomplete[index];
+            }
+
+            return replace;
+        }
     }
 }
diff --git a/src/Spectre.Console/Internal/TypeConverterHelper.cs b/src/Spectre.Console/Internal/TypeConverterHelper.cs
new file mode 100644
index 0000000..07d847e
--- /dev/null
+++ b/src/Spectre.Console/Internal/TypeConverterHelper.cs
@@ -0,0 +1,55 @@
+using System;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+
+namespace Spectre.Console.Internal
+{
+    internal static class TypeConverterHelper
+    {
+        public static string ConvertToString<T>(T input)
+        {
+            return GetTypeConverter<T>().ConvertToInvariantString(input);
+        }
+
+        [SuppressMessage("Design", "CA1031:Do not catch general exception types")]
+        public static bool TryConvertFromString<T>(string input, [MaybeNull] out T result)
+        {
+            try
+            {
+                result = (T)GetTypeConverter<T>().ConvertFromInvariantString(input);
+                return true;
+            }
+            catch
+            {
+                result = default;
+                return false;
+            }
+        }
+
+        public static TypeConverter GetTypeConverter<T>()
+        {
+            var converter = TypeDescriptor.GetConverter(typeof(T));
+            if (converter != null)
+            {
+                return converter;
+            }
+
+            var attribute = typeof(T).GetCustomAttribute<TypeConverterAttribute>();
+            if (attribute != null)
+            {
+                var type = Type.GetType(attribute.ConverterTypeName, false, false);
+                if (type != null)
+                {
+                    converter = Activator.CreateInstance(type) as TypeConverter;
+                    if (converter != null)
+                    {
+                        return converter;
+                    }
+                }
+            }
+
+            throw new InvalidOperationException("Could not find type converter");
+        }
+    }
+}
diff --git a/src/Spectre.Console/Spectre.Console.csproj b/src/Spectre.Console/Spectre.Console.csproj
index 7a3d999..4db6bb2 100644
--- a/src/Spectre.Console/Spectre.Console.csproj
+++ b/src/Spectre.Console/Spectre.Console.csproj
@@ -2,16 +2,17 @@
 
   <PropertyGroup>
     <TargetFrameworks>net5.0;netstandard2.0</TargetFrameworks>
+    <LangVersion>9.0</LangVersion>
     <Nullable>enable</Nullable>
   </PropertyGroup>
 
   <ItemGroup>
-    <None Remove="Figlet\Fonts\Standard.flf" />
+    <None Remove="Widgets\Figlet\Fonts\Standard.flf" />
   </ItemGroup>
 
   <ItemGroup>
     <AdditionalFiles Include="..\stylecop.json" Link="Properties/stylecop.json" />
-    <EmbeddedResource Include="Figlet\Fonts\Standard.flf" />
+    <EmbeddedResource Include="Widgets\Figlet\Fonts\Standard.flf" />
     <None Include="../../resources/gfx/small-logo.png" Pack="true" PackagePath="\" Link="Properties/small-logo.png" />
   </ItemGroup>
 
diff --git a/src/Spectre.Console/Figlet/FigletCharacter.cs b/src/Spectre.Console/Widgets/Figlet/FigletCharacter.cs
similarity index 100%
rename from src/Spectre.Console/Figlet/FigletCharacter.cs
rename to src/Spectre.Console/Widgets/Figlet/FigletCharacter.cs
diff --git a/src/Spectre.Console/Figlet/FigletFont.cs b/src/Spectre.Console/Widgets/Figlet/FigletFont.cs
similarity index 94%
rename from src/Spectre.Console/Figlet/FigletFont.cs
rename to src/Spectre.Console/Widgets/Figlet/FigletFont.cs
index bb86cd9..c388cef 100644
--- a/src/Spectre.Console/Figlet/FigletFont.cs
+++ b/src/Spectre.Console/Widgets/Figlet/FigletFont.cs
@@ -10,6 +10,8 @@ namespace Spectre.Console
     /// </summary>
     public sealed class FigletFont
     {
+        private const string StandardFont = "Spectre.Console/Widgets/Figlet/Fonts/Standard.flf";
+
         private readonly Dictionary<int, FigletCharacter> _characters;
         private static readonly Lazy<FigletFont> _standard;
 
@@ -40,7 +42,8 @@ namespace Spectre.Console
 
         static FigletFont()
         {
-            _standard = new Lazy<FigletFont>(() => Parse(ResourceReader.ReadManifestData("Spectre.Console/Figlet/Fonts/Standard.flf")));
+            _standard = new Lazy<FigletFont>(() => Parse(
+                ResourceReader.ReadManifestData(StandardFont)));
         }
 
         internal FigletFont(IEnumerable<FigletCharacter> characters, FigletHeader header)
diff --git a/src/Spectre.Console/Figlet/FigletFontParser.cs b/src/Spectre.Console/Widgets/Figlet/FigletFontParser.cs
similarity index 100%
rename from src/Spectre.Console/Figlet/FigletFontParser.cs
rename to src/Spectre.Console/Widgets/Figlet/FigletFontParser.cs
diff --git a/src/Spectre.Console/Figlet/FigletHeader.cs b/src/Spectre.Console/Widgets/Figlet/FigletHeader.cs
similarity index 100%
rename from src/Spectre.Console/Figlet/FigletHeader.cs
rename to src/Spectre.Console/Widgets/Figlet/FigletHeader.cs
diff --git a/src/Spectre.Console/Figlet/FigletText.cs b/src/Spectre.Console/Widgets/Figlet/FigletText.cs
similarity index 100%
rename from src/Spectre.Console/Figlet/FigletText.cs
rename to src/Spectre.Console/Widgets/Figlet/FigletText.cs
diff --git a/src/Spectre.Console/Figlet/Fonts/Standard.flf b/src/Spectre.Console/Widgets/Figlet/Fonts/Standard.flf
similarity index 100%
rename from src/Spectre.Console/Figlet/Fonts/Standard.flf
rename to src/Spectre.Console/Widgets/Figlet/Fonts/Standard.flf
diff --git a/src/Spectre.Console/Progress/Columns/PercentageColumn.cs b/src/Spectre.Console/Widgets/Progress/Columns/PercentageColumn.cs
similarity index 100%
rename from src/Spectre.Console/Progress/Columns/PercentageColumn.cs
rename to src/Spectre.Console/Widgets/Progress/Columns/PercentageColumn.cs
diff --git a/src/Spectre.Console/Progress/Columns/ProgressBarColumn.cs b/src/Spectre.Console/Widgets/Progress/Columns/ProgressBarColumn.cs
similarity index 100%
rename from src/Spectre.Console/Progress/Columns/ProgressBarColumn.cs
rename to src/Spectre.Console/Widgets/Progress/Columns/ProgressBarColumn.cs
diff --git a/src/Spectre.Console/Progress/Columns/RemainingTimeColumn.cs b/src/Spectre.Console/Widgets/Progress/Columns/RemainingTimeColumn.cs
similarity index 100%
rename from src/Spectre.Console/Progress/Columns/RemainingTimeColumn.cs
rename to src/Spectre.Console/Widgets/Progress/Columns/RemainingTimeColumn.cs
diff --git a/src/Spectre.Console/Progress/Columns/SpinnerColumn.cs b/src/Spectre.Console/Widgets/Progress/Columns/SpinnerColumn.cs
similarity index 100%
rename from src/Spectre.Console/Progress/Columns/SpinnerColumn.cs
rename to src/Spectre.Console/Widgets/Progress/Columns/SpinnerColumn.cs
diff --git a/src/Spectre.Console/Progress/Columns/TaskDescriptionColumn.cs b/src/Spectre.Console/Widgets/Progress/Columns/TaskDescriptionColumn.cs
similarity index 100%
rename from src/Spectre.Console/Progress/Columns/TaskDescriptionColumn.cs
rename to src/Spectre.Console/Widgets/Progress/Columns/TaskDescriptionColumn.cs
diff --git a/src/Spectre.Console/Progress/Progress.cs b/src/Spectre.Console/Widgets/Progress/Progress.cs
similarity index 100%
rename from src/Spectre.Console/Progress/Progress.cs
rename to src/Spectre.Console/Widgets/Progress/Progress.cs
diff --git a/src/Spectre.Console/Progress/ProgressColumn.cs b/src/Spectre.Console/Widgets/Progress/ProgressColumn.cs
similarity index 100%
rename from src/Spectre.Console/Progress/ProgressColumn.cs
rename to src/Spectre.Console/Widgets/Progress/ProgressColumn.cs
diff --git a/src/Spectre.Console/Progress/ProgressContext.cs b/src/Spectre.Console/Widgets/Progress/ProgressContext.cs
similarity index 100%
rename from src/Spectre.Console/Progress/ProgressContext.cs
rename to src/Spectre.Console/Widgets/Progress/ProgressContext.cs
diff --git a/src/Spectre.Console/Progress/ProgressRefreshThread.cs b/src/Spectre.Console/Widgets/Progress/ProgressRefreshThread.cs
similarity index 100%
rename from src/Spectre.Console/Progress/ProgressRefreshThread.cs
rename to src/Spectre.Console/Widgets/Progress/ProgressRefreshThread.cs
diff --git a/src/Spectre.Console/Progress/ProgressRenderer.cs b/src/Spectre.Console/Widgets/Progress/ProgressRenderer.cs
similarity index 100%
rename from src/Spectre.Console/Progress/ProgressRenderer.cs
rename to src/Spectre.Console/Widgets/Progress/ProgressRenderer.cs
diff --git a/src/Spectre.Console/Progress/ProgressSample.cs b/src/Spectre.Console/Widgets/Progress/ProgressSample.cs
similarity index 100%
rename from src/Spectre.Console/Progress/ProgressSample.cs
rename to src/Spectre.Console/Widgets/Progress/ProgressSample.cs
diff --git a/src/Spectre.Console/Progress/ProgressTask.cs b/src/Spectre.Console/Widgets/Progress/ProgressTask.cs
similarity index 100%
rename from src/Spectre.Console/Progress/ProgressTask.cs
rename to src/Spectre.Console/Widgets/Progress/ProgressTask.cs
diff --git a/src/Spectre.Console/Progress/ProgressTaskSettings.cs b/src/Spectre.Console/Widgets/Progress/ProgressTaskSettings.cs
similarity index 100%
rename from src/Spectre.Console/Progress/ProgressTaskSettings.cs
rename to src/Spectre.Console/Widgets/Progress/ProgressTaskSettings.cs
diff --git a/src/Spectre.Console/Progress/ProgressTaskState.cs b/src/Spectre.Console/Widgets/Progress/ProgressTaskState.cs
similarity index 100%
rename from src/Spectre.Console/Progress/ProgressTaskState.cs
rename to src/Spectre.Console/Widgets/Progress/ProgressTaskState.cs
diff --git a/src/Spectre.Console/Progress/Renderers/DefaultProgressRenderer.cs b/src/Spectre.Console/Widgets/Progress/Renderers/DefaultProgressRenderer.cs
similarity index 100%
rename from src/Spectre.Console/Progress/Renderers/DefaultProgressRenderer.cs
rename to src/Spectre.Console/Widgets/Progress/Renderers/DefaultProgressRenderer.cs
diff --git a/src/Spectre.Console/Progress/Renderers/FallbackProgressRenderer.cs b/src/Spectre.Console/Widgets/Progress/Renderers/FallbackProgressRenderer.cs
similarity index 100%
rename from src/Spectre.Console/Progress/Renderers/FallbackProgressRenderer.cs
rename to src/Spectre.Console/Widgets/Progress/Renderers/FallbackProgressRenderer.cs
diff --git a/src/Spectre.Console/Progress/Renderers/StatusFallbackRenderer.cs b/src/Spectre.Console/Widgets/Progress/Renderers/StatusFallbackRenderer.cs
similarity index 100%
rename from src/Spectre.Console/Progress/Renderers/StatusFallbackRenderer.cs
rename to src/Spectre.Console/Widgets/Progress/Renderers/StatusFallbackRenderer.cs
diff --git a/src/Spectre.Console/Progress/Spinner.Generated.cs b/src/Spectre.Console/Widgets/Progress/Spinner.Generated.cs
similarity index 100%
rename from src/Spectre.Console/Progress/Spinner.Generated.cs
rename to src/Spectre.Console/Widgets/Progress/Spinner.Generated.cs
diff --git a/src/Spectre.Console/Progress/Spinner.cs b/src/Spectre.Console/Widgets/Progress/Spinner.cs
similarity index 100%
rename from src/Spectre.Console/Progress/Spinner.cs
rename to src/Spectre.Console/Widgets/Progress/Spinner.cs
diff --git a/src/Spectre.Console/Progress/Status.cs b/src/Spectre.Console/Widgets/Progress/Status.cs
similarity index 100%
rename from src/Spectre.Console/Progress/Status.cs
rename to src/Spectre.Console/Widgets/Progress/Status.cs
diff --git a/src/Spectre.Console/Progress/StatusContext.cs b/src/Spectre.Console/Widgets/Progress/StatusContext.cs
similarity index 100%
rename from src/Spectre.Console/Progress/StatusContext.cs
rename to src/Spectre.Console/Widgets/Progress/StatusContext.cs
diff --git a/src/Spectre.Console/Widgets/Prompt/DefaultPromptValue.cs b/src/Spectre.Console/Widgets/Prompt/DefaultPromptValue.cs
new file mode 100644
index 0000000..c78b210
--- /dev/null
+++ b/src/Spectre.Console/Widgets/Prompt/DefaultPromptValue.cs
@@ -0,0 +1,12 @@
+namespace Spectre.Console
+{
+    internal sealed class DefaultPromptValue<T>
+    {
+        public T Value { get; }
+
+        public DefaultPromptValue(T value)
+        {
+            Value = value;
+        }
+    }
+}
diff --git a/src/Spectre.Console/IPrompt.cs b/src/Spectre.Console/Widgets/Prompt/IPrompt.cs
similarity index 100%
rename from src/Spectre.Console/IPrompt.cs
rename to src/Spectre.Console/Widgets/Prompt/IPrompt.cs
diff --git a/src/Spectre.Console/TextPrompt.cs b/src/Spectre.Console/Widgets/Prompt/TextPrompt.cs
similarity index 67%
rename from src/Spectre.Console/TextPrompt.cs
rename to src/Spectre.Console/Widgets/Prompt/TextPrompt.cs
index e50484c..e6cb2ef 100644
--- a/src/Spectre.Console/TextPrompt.cs
+++ b/src/Spectre.Console/Widgets/Prompt/TextPrompt.cs
@@ -1,11 +1,10 @@
 using System;
 using System.Collections.Generic;
-using System.ComponentModel;
 using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
 using System.Linq;
-using System.Reflection;
 using System.Text;
+using Spectre.Console.Internal;
 
 namespace Spectre.Console
 {
@@ -68,27 +67,7 @@ namespace Spectre.Console
         /// <summary>
         /// Gets or sets the default value.
         /// </summary>
-        internal DefaultValueContainer? DefaultValue { get; set; }
-
-        /// <summary>
-        /// A nullable container for a default value.
-        /// </summary>
-        internal sealed class DefaultValueContainer
-        {
-            /// <summary>
-            /// Gets the default value.
-            /// </summary>
-            public T Value { get; }
-
-            /// <summary>
-            /// Initializes a new instance of the <see cref="DefaultValueContainer"/> class.
-            /// </summary>
-            /// <param name="value">The default value.</param>
-            public DefaultValueContainer(T value)
-            {
-                Value = value;
-            }
-        }
+        internal DefaultPromptValue<T>? DefaultValue { get; set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="TextPrompt{T}"/> class.
@@ -116,19 +95,20 @@ namespace Spectre.Console
             }
 
             var promptStyle = PromptStyle ?? Style.Plain;
+            var choices = Choices.Select(choice => TypeConverterHelper.ConvertToString(choice));
 
             WritePrompt(console);
 
             while (true)
             {
-                var input = console.ReadLine(promptStyle, IsSecret);
+                var input = console.ReadLine(promptStyle, IsSecret, choices);
 
                 // Nothing entered?
                 if (string.IsNullOrWhiteSpace(input))
                 {
                     if (DefaultValue != null)
                     {
-                        console.Write(TextPrompt<T>.GetTypeConverter().ConvertToInvariantString(DefaultValue.Value), promptStyle);
+                        console.Write(TypeConverterHelper.ConvertToString(DefaultValue.Value), promptStyle);
                         console.WriteLine();
                         return DefaultValue.Value;
                     }
@@ -142,7 +122,7 @@ namespace Spectre.Console
                 console.WriteLine();
 
                 // Try convert the value to the expected type.
-                if (!TextPrompt<T>.TryConvert(input, out var result) || result == null)
+                if (!TypeConverterHelper.TryConvertFromString<T>(input, out var result) || result == null)
                 {
                     console.MarkupLine(ValidationErrorMessage);
                     WritePrompt(console);
@@ -191,7 +171,7 @@ namespace Spectre.Console
 
             if (ShowChoices && Choices.Count > 0)
             {
-                var choices = string.Join("/", Choices.Select(choice => TextPrompt<T>.GetTypeConverter().ConvertToInvariantString(choice)));
+                var choices = string.Join("/", Choices.Select(choice => TypeConverterHelper.ConvertToString(choice)));
                 builder.AppendFormat(CultureInfo.InvariantCulture, " [blue][[{0}]][/]", choices);
             }
 
@@ -200,7 +180,7 @@ namespace Spectre.Console
                 builder.AppendFormat(
                     CultureInfo.InvariantCulture,
                     " [green]({0})[/]",
-                    TextPrompt<T>.GetTypeConverter().ConvertToInvariantString(DefaultValue.Value));
+                    TypeConverterHelper.ConvertToString(DefaultValue.Value));
             }
 
             var markup = builder.ToString().Trim();
@@ -213,58 +193,6 @@ namespace Spectre.Console
             console.Markup(markup + " ");
         }
 
-        /// <summary>
-        /// Tries to convert the input string to <typeparamref name="T"/>.
-        /// </summary>
-        /// <param name="input">The input to convert.</param>
-        /// <param name="result">The result.</param>
-        /// <returns><c>true</c> if the conversion succeeded, otherwise <c>false</c>.</returns>
-        [SuppressMessage("Design", "CA1031:Do not catch general exception types")]
-        private static bool TryConvert(string input, [MaybeNull] out T result)
-        {
-            try
-            {
-                result = (T)TextPrompt<T>.GetTypeConverter().ConvertFromInvariantString(input);
-                return true;
-            }
-            catch
-            {
-#pragma warning disable CS8601 // Possible null reference assignment.
-                result = default;
-#pragma warning restore CS8601 // Possible null reference assignment.
-                return false;
-            }
-        }
-
-        /// <summary>
-        /// Gets the type converter that's used to convert values.
-        /// </summary>
-        /// <returns>The type converter that's used to convert values.</returns>
-        private static TypeConverter GetTypeConverter()
-        {
-            var converter = TypeDescriptor.GetConverter(typeof(T));
-            if (converter != null)
-            {
-                return converter;
-            }
-
-            var attribute = typeof(T).GetCustomAttribute<TypeConverterAttribute>();
-            if (attribute != null)
-            {
-                var type = Type.GetType(attribute.ConverterTypeName, false, false);
-                if (type != null)
-                {
-                    converter = Activator.CreateInstance(type) as TypeConverter;
-                    if (converter != null)
-                    {
-                        return converter;
-                    }
-                }
-            }
-
-            throw new InvalidOperationException("Could not find type converter");
-        }
-
         private bool ValidateResult(T value, [NotNullWhen(false)] out string? message)
         {
             if (Validator != null)
diff --git a/src/Spectre.Console/Extensions/TextPromptExtensions.cs b/src/Spectre.Console/Widgets/Prompt/TextPromptExtensions.cs
similarity index 99%
rename from src/Spectre.Console/Extensions/TextPromptExtensions.cs
rename to src/Spectre.Console/Widgets/Prompt/TextPromptExtensions.cs
index 1cfa1c0..9713ea1 100644
--- a/src/Spectre.Console/Extensions/TextPromptExtensions.cs
+++ b/src/Spectre.Console/Widgets/Prompt/TextPromptExtensions.cs
@@ -177,7 +177,7 @@ namespace Spectre.Console
                 throw new ArgumentNullException(nameof(obj));
             }
 
-            obj.DefaultValue = new TextPrompt<T>.DefaultValueContainer(value);
+            obj.DefaultValue = new DefaultPromptValue<T>(value);
             return obj;
         }
 
diff --git a/src/Spectre.Console/ValidationResult.cs b/src/Spectre.Console/Widgets/Prompt/ValidationResult.cs
similarity index 94%
rename from src/Spectre.Console/ValidationResult.cs
rename to src/Spectre.Console/Widgets/Prompt/ValidationResult.cs
index d96f413..90d7167 100644
--- a/src/Spectre.Console/ValidationResult.cs
+++ b/src/Spectre.Console/Widgets/Prompt/ValidationResult.cs
@@ -1,7 +1,7 @@
-﻿namespace Spectre.Console
+namespace Spectre.Console
 {
     /// <summary>
-    /// Represents a validation result.
+    /// Represents a prompt validation result.
     /// </summary>
     public sealed class ValidationResult
     {
