← Back to Home • Next: TableSelect — Operations →
Every fluent method on ITableSelectControl<T>. Each returns the same control instance, so calls chain
in any order. Call Run last.
The factory is
PromptPlus.Controls.TableSelect<T>(string prompt = "", string? description = null), which returnsITableSelectControl<T>.
Quick jump: AddColumn · AddItem · AddItems · Interaction · InteractionAsync · TextSelector · TextSelectorAsync · ChangeDescription · ChangeDescriptionAsync · Filter · PageSize · LayoutMode · HideElements · HorizontalScroll · Default · UseDefaultHistory · DefaultMatchBy · PredicateSelected · PredicateSelectedAsync · ViewOnly · EnableHistory · Styles · Options · Run
AddColumnITableSelectControl<T> AddColumn(
string header,
Func<T, object> selector,
Func<object, string>? formatter = null,
int? width = null,
ColumnAlignment alignment = ColumnAlignment.Left,
bool isFilterable = false)
Adds a column. Signature is header-first: the header text comes before the value selector.
At least one column must be added before Run.
| Parameter | Meaning |
|---|---|
header |
Column title. Cannot be null, empty, or whitespace. |
selector |
Extracts the cell value from a row. |
formatter |
Optional — converts the raw cell value to its display string. null uses ToString(). |
width |
Fixed column width in characters. null (default) auto-sizes from the header and cell values at Run time. Must be greater than zero when specified. |
alignment |
Cell content alignment — ColumnAlignment. Default Left. |
isFilterable |
When true, this column’s cells participate in filter matching (see Filter). Default false. |
PromptPlus.Controls.TableSelect<Product>("Select a product")
.AddColumn("Id", x => x.Id, width: 4, alignment: ColumnAlignment.Right)
.AddColumn("Name", x => x.Name, isFilterable: true)
.AddColumn("Category", x => x.Category, alignment: ColumnAlignment.Center)
.AddColumn("Price", x => x.Price, v => $"$ {v:N2}", alignment: ColumnAlignment.Right)
.AddItems(products)
.Run();
Throws
ArgumentNullExceptionifheaderorselectorisnull,ArgumentExceptionifheaderis empty/whitespace, andArgumentOutOfRangeExceptionifwidthis specified and not greater than zero.
AddItemITableSelectControl<T> AddItem(T value, bool disable = false)
Adds a single row. Set disable: true to show it but make it non-selectable. At least one row must be
added before Run.
PromptPlus.Controls.TableSelect<Product>("Product")
.AddColumn("Name", x => x.Name)
.AddItem(products[0])
.AddItem(products[1], disable: true) // visible but not selectable
.Run();
Throws
ArgumentNullExceptionifvalueisnull.
AddItemsITableSelectControl<T> AddItems(IEnumerable<T> values, bool disable = false)
Adds many rows at once. disable: true disables all of them.
PromptPlus.Controls.TableSelect<Product>("Product")
.AddColumn("Name", x => x.Name)
.AddItems(products)
.Run();
Throws
ArgumentNullExceptionifvaluesisnull.
InteractionITableSelectControl<T> Interaction<T1>(IEnumerable<T1> items, Action<T1, ITableSelectControl<T>> interactionAction)
Iterates a source collection and lets you add rows programmatically — useful for per-item logic such as disabling rows conditionally.
PromptPlus.Controls.TableSelect<Product>("Select an available product")
.AddColumn("Name", x => x.Name)
.AddColumn("Available", x => x.Available ? "Yes" : "No", alignment: ColumnAlignment.Center, width: 10)
.Interaction(products, (p, ctrl) => ctrl.AddItem(p, disable: !p.Available))
.Run();
InteractionAsyncITableSelectControl<T> InteractionAsync<T1>(IEnumerable<T1> items, Func<T1, ITableSelectControl<T>, Task> interactionAction)
Asynchronous version of Interaction; each task is awaited synchronously.
TextSelectorITableSelectControl<T> TextSelector(Func<T, string> value)
Sets the answer text shown after the control completes. Without it (and without
TextSelectorAsync), the confirmed row’s ToString() is used.
PromptPlus.Controls.TableSelect<Product>("Product")
.AddColumn("Name", x => x.Name)
.AddColumn("Price", x => x.Price, v => $"${v:N2}", alignment: ColumnAlignment.Right)
.AddItems(products)
.TextSelector(item => $"{item.Name} (${item.Price:N2})")
.Run();
TextSelectorAsyncITableSelectControl<T> TextSelectorAsync(Func<T, Task<string>> value)
Asynchronous version of TextSelector.
ChangeDescriptionITableSelectControl<T> ChangeDescription(Func<T, string> value)
Recomputes the description line from the currently highlighted row as the user navigates.
PromptPlus.Controls.TableSelect<Product>("Product")
.AddColumn("Name", x => x.Name)
.AddItems(products)
.ChangeDescription(item => $"Category: {item.Category} | Origin: {item.Origin}")
.Run();
Throws
ArgumentNullExceptionifvalueisnull.
ChangeDescriptionAsyncITableSelectControl<T> ChangeDescriptionAsync(Func<T, Task<string>> value)
Asynchronous version of ChangeDescription.
FilterITableSelectControl<T> Filter(FilterMode value, FilterTableMode filterby = FilterTableMode.Answer)
Enables live filtering as the user types. Default is FilterMode.Disabled with FilterTableMode.Answer.
FilterMode |
Behavior |
|---|---|
Disabled |
No filtering (default) |
Contains |
Match rows containing the typed text |
StartsWith |
Match rows starting with the typed text |
FilterTableMode |
What the filter matches against |
|---|---|
Answer |
The answer text (result of TextSelector) |
ColumnFilters |
The concatenated text of every column declared with isFilterable: true |
PromptPlus.Controls.TableSelect<Product>("Search product")
.AddColumn("Name", x => x.Name, isFilterable: true)
.AddColumn("Category", x => x.Category, isFilterable: true)
.AddColumn("Origin", x => x.Origin, isFilterable: true)
.AddItems(products)
.Filter(FilterMode.Contains, FilterTableMode.ColumnFilters)
.Run();
PageSizeITableSelectControl<T> PageSize(byte value)
Maximum rows per page (valid range 0–255). 0 (default) auto-computes from the terminal height.
PromptPlus.Controls.TableSelect<Product>("Product").AddColumn("Name", x => x.Name).AddItems(products).PageSize(8).Run();
LayoutModeITableSelectControl<T> LayoutMode(TableLayoutMode mode)
Sets the box-drawing character set for borders. Default SingleBox.
TableLayoutMode |
Renders |
|---|---|
SingleBox |
Single Unicode box-drawing lines (default) |
DoubleBox |
Double Unicode box-drawing lines |
SingleASCII |
Single lines using plain ASCII characters |
DoubleASCII |
Double lines using plain ASCII characters |
None |
No border characters at all |
PromptPlus.Controls.TableSelect<Product>("Product")
.LayoutMode(TableLayoutMode.DoubleBox)
.AddColumn("Name", x => x.Name)
.AddItems(products)
.Run();
HideElementsITableSelectControl<T> HideElements(HideTable borders)
Hides one or more border regions. HideTable is a [Flags] enum — combine with |. Default
HideTable.None (everything visible).
HideTable |
Hides |
|---|---|
None |
Nothing — show all elements (default) |
RowSeparator |
Horizontal separators between data rows |
Header |
The entire header row and the header/data separator line |
ColumnSeparator |
Vertical separators between columns |
OuterBorder |
The outer frame (top, bottom, left, right edges) |
PromptPlus.Controls.TableSelect<Product>("Product")
.HideElements(HideTable.OuterBorder | HideTable.RowSeparator)
.AddColumn("Name", x => x.Name)
.AddItems(products)
.Run();
HorizontalScrollITableSelectControl<T> HorizontalScroll(HorizontalScrollMode mode)
Controls how columns scroll once they no longer all fit on screen. Default Full. Tab / Shift+Tab
always move the focused column and wrap around at the first/last column, even when every column already
fits and nothing needs to scroll — this setting only changes the viewport behavior once scrolling
actually kicks in.
HorizontalScrollMode |
Behavior |
|---|---|
Full |
Moves the visible viewport as a full column window |
Column |
Scrolls by focusing columns one at a time |
PromptPlus.Controls.TableSelect<Employee>("Employee")
.HorizontalScroll(HorizontalScrollMode.Column)
// ... 12 columns ...
.AddItems(employees)
.Run();
DefaultITableSelectControl<T> Default(T value, bool useDefaultHistory = true)
Pre-selects value as the initial cursor position, matched with DefaultMatchBy
(default: EqualityComparer<T>.Default). Disabled rows and rows rejected by a selection predicate are
not pre-selected. When useDefaultHistory is true and history is enabled, the most
recent history entry overrides this value.
PromptPlus.Controls.TableSelect<Product>("Product")
.AddColumn("Name", x => x.Name)
.AddItems(products)
.DefaultMatchBy((a, b) => a.Id == b.Id)
.Default(products[0])
.Run();
Throws
ArgumentNullExceptionifvalueisnull.
UseDefaultHistoryITableSelectControl<T> UseDefaultHistory()
Sets the initial cursor to the most recent history entry, clearing any value set by Default.
Has no effect unless EnableHistory is set.
DefaultMatchByITableSelectControl<T> DefaultMatchBy(Func<T, T, bool> comparer)
Custom equality used to locate the Default row and match history values — essential for
records/classes where reference equality is not meaningful.
PromptPlus.Controls.TableSelect<Product>("Product")
.AddColumn("Name", x => x.Name)
.AddItems(products)
.DefaultMatchBy((a, b) => a.Id == b.Id)
.Default(new Product(4, "New York", "any", 0m))
.Run();
Throws
ArgumentNullExceptionifcomparerisnull.
Validation runs on Enter. On failure the table stays open and shows an error line.
PredicateSelectedITableSelectControl<T> PredicateSelected(Func<T, bool> validselect)
ITableSelectControl<T> PredicateSelected(Func<T, (bool, string?)> validselect)
| Overload | Return | Behavior |
|---|---|---|
Func<T, bool> |
true = valid |
Generic error on failure |
Func<T, (bool, string?)> |
(isValid, message) |
Custom message on failure |
Setting a synchronous predicate replaces any previously registered asynchronous one.
PromptPlus.Controls.TableSelect<Product>("Product")
.AddColumn("Name", x => x.Name)
.AddColumn("Category", x => x.Category)
.AddItems(products)
.PredicateSelected(p => p.Category is "Electronics" or "Peripherals"
? (true, null)
: (false, $"Category '{p.Category}' is not allowed."))
.Run();
Throws
ArgumentNullExceptionifvalidselectisnull.
PredicateSelectedAsyncITableSelectControl<T> PredicateSelectedAsync(Func<T, Task<bool>> validselect)
ITableSelectControl<T> PredicateSelectedAsync(Func<T, Task<(bool, string?)>> validselect)
Asynchronous counterparts; setting one replaces any previously registered synchronous predicate.
⚠️ The async predicate is awaited synchronously (blocking) on the UI thread — keep it fast.
ViewOnlyITableSelectControl<T> ViewOnly(bool value = true)
Renders the table for browsing only — the user can navigate freely but cannot change the selection. On
Enter the control always returns the item highlighted at startup (set via Default or the
first row), regardless of where the user browsed. Selection predicates and disabled-row restrictions are
not enforced in this mode. Default false.
PromptPlus.Controls.TableSelect<Product>("Product catalogue (view only)", "Press Esc or Enter to exit")
.AddColumn("Name", x => x.Name)
.AddColumn("Price", x => x.Price, v => $"${v:N2}", alignment: ColumnAlignment.Right)
.AddItems(products)
.PageSize(4)
.ViewOnly()
.Run();
EnableHistoryITableSelectControl<T> EnableHistory(string filename, Action<IHistoryOptions>? options = null)
Persists confirmed selections to filename and can pre-select the last one (via Default or
UseDefaultHistory). The IHistoryOptions builder is identical to the one
documented for Input → EnableHistory (MinPrefixLength, MaxItems,
ExpirationTime, FilterType, PageSize).
PromptPlus.Controls.TableSelect<Product>("Product")
.AddColumn("Id", x => x.Id, width: 4, alignment: ColumnAlignment.Right)
.AddColumn("Name", x => x.Name)
.AddItems(products)
.DefaultMatchBy((a, b) => a.Id == b.Id)
.EnableHistory("table-product-history")
.UseDefaultHistory()
.Run();
Throws
ArgumentNullExceptioniffilenameisnull,ArgumentExceptionif it is empty/whitespace.
StylesITableSelectControl<T> Styles(TableSelectStyles styleType, Style style)
Recolors one visual region of this control. See the region list and examples on the Styles page.
using PromptPlusLibrary;
using ConsolePlusLibrary; // Color, Style live here
PromptPlus.Controls.TableSelect<Product>("Product")
.AddColumn("Name", x => x.Name)
.AddItems(products)
.Styles(TableSelectStyles.SelectedCell, new Style(Color.Black, Color.Cyan))
.Run();
OptionsITableSelectControl<T> Options(Action<IControlOptions> options)
Overrides global behaviors for this one control (prompt/description text, abort key, tooltip, hide-after-finish). See Global Behaviors → Per-Control Override.
Throws
ArgumentNullExceptionifoptionsisnull.
RunResultPrompt<TableSelectResult<T>> Run(CancellationToken token = default)
Renders the table and blocks until the user confirms (Enter) or aborts (Esc). Returns
ResultPrompt<TableSelectResult<T>>; the TableSelectResult<T> exposes
.Value, .RowIndex, .ColumnIndex, and deconstructs into (value, row, column).
var result = PromptPlus.Controls.TableSelect<Product>("Product")
.AddColumn("Name", x => x.Name)
.AddItems(products)
.Run();
if (!result.IsAborted)
PromptPlus.Console.WriteLine(result.Content.Value.Name);
TableSelectStyles regions