An opinionated, component-based UI framework for .NET console applications. Build terminal interfaces with tables, menus, progress bars, spinners, layout containers, and more.
- ๐ Features
- ๐ฆ Installation
- ๐ Usage Guide
- ๐จ Theming
- ๐๏ธ Architecture
- ๐ป Requirements
- ๐ Licence
- ๐ค Contributing
- Theming System โ Fully composable themes combining colour schemes and border styles, with built-in presets
- Semantic Colour Output โ Contextual coloured text for errors, success, warnings, and information
- Rich Components โ Tables, menus, progress bars, spinners, and notifications
- Layout Containers โ Panel, Row, Column, and Viewport for structured terminal layouts
- Renderer Abstraction โ Swap rendering backends for testing or deferred output via
IRenderer - Scoped Theming โ Apply themes globally or per-component, with scoped overrides via
ConsoleContext
dotnet add package ConsolePrism- Clone the repository
- Add a reference to your project:
dotnet add reference path/to/src/ConsolePrism.csprojusing ConsolePrism.Core;
ColorWriter.WriteSuccessLine("Operation completed!");
ColorWriter.WriteErrorLine("Something went wrong.");
ColorWriter.WriteWarningLine("Proceed with caution.");
ColorWriter.WriteInfoLine("Here is some information.");
ColorWriter.WriteHighlightLine("Important text.");
// Explicit colour when needed
ColorWriter.WriteColoredLine("Custom text", ConsoleColor.Magenta);using ConsolePrism.Components;
// Arrow-key interactive menu (default)
string[] choices = ["New Game", "Continue", "Settings", "Exit"];
Menu interactive = new("Main Menu", MenuStyle.Interactive, choices);
int choice = interactive.Interact();
// Numbered menu
Menu numbered = new("Select Difficulty", MenuStyle.Numbered, "Easy", "Normal", "Hard");
int difficulty = numbered.Interact();
// Bordered menu
Menu bordered = new("Choose Mode", MenuStyle.Bordered, "Story", "Creative", "Survival");
int mode = bordered.Interact();using ConsolePrism.Components;
string[] headers = ["Name", "Score", "Level"];
string[][] data = [
["Alice", "1250", "10"],
["Bob", "980", "8" ],
["Charlie", "1500", "12"],
]; // Can be nullable for empty cells
new Table(headers, data).Render();
// Alternatively for coloured cells
TableCell[][] colouredData = [
["Alice", new TableCell("1250", ConsoleColor.Green), "10"],
["Bob", new TableCell("980", ConsoleColor.Red), "8" ],
["Charlie", new TableCell("1500", ConsoleColor.Yellow),"12"],
];
new Table(headers, colouredData).Render();
// Custom column widths
int[] widths = [15, 10, 8];
new Table(headers, data, widths).Render();using ConsolePrism.Components;
// Static progress bar
new ProgressBar(75, "Processing", 100).Render();
// Animated in-place progress
ProgressBar bar = new(0, "Loading", 100) { InPlace = true };
for (int i = 0; i <= 100; i++)
{
bar.Current = i;
bar.Render();
Thread.Sleep(50);
}using ConsolePrism.Components;
Spinner spinner = new(Spinner.Dots, "Loading assets...");
spinner.Start();
// Do work...
await LoadAssetsAsync();
spinner.Stop("Assets loaded successfully!");
// Using Dispose pattern
using Spinner spinner = new(Spinner.Pulse, "Connecting...");
spinner.Start();
await ConnectAsync();using ConsolePrism.Components;
new Notification("File saved!", false, NotificationLevel.Success).Render();
new Notification("Low disk space.", false, NotificationLevel.Warning).Render();
new Notification("Connection failed.", false NotificationLevel.Error).Render();
// Transient notification
new Notification("Autosaving...", false, NotificationLevel.Info, 2000).Render();
// Bordered notification
new Notification("Welcome to ConsolePrism!", true, NotificationLevel.Info).Render();using ConsolePrism.Components;
// Simple text
new ConsoleText("This is a simple text component.").Render();
// Text with colour
new ConsoleText("This is an error message.", ConsoleColor.Red).Render();
// Note: This has been implemented with the sole purpose of for ease of use in the panel, column, row and viewport layouts.using ConsolePrism.Layout;
Panel simplePanel = new(
content: new ConsoleText("This is a simple panel.") // Or any component
);
// Complex panel with title, content, and padding
Panel panel = new(
title: "Welcome",
content: new ConsoleText("Hello, World!"),
horizontalPadding: 2,
verticalPadding: 1
);
panel.Render();using ConsolePrism.Layout;
Row row = new(
spacing: 1,
new ConsoleText("Header"),
new Panel(title: "Info", content: new ConsoleText("Details...")),
new ConsoleText("Footer")
);
row.Render();
// Alternatively through Fluent API:
Row fluentRow = new Row(spacing: 1)
.Add(new ConsoleText("Header"))
.Add(new Panel(title: "Info", content: new ConsoleText("Details...")))
.Add(new ConsoleText("Footer"));
fluentRow.Render();using ConsolePrism.Layout;
Viewport viewport = new(
height: 2,
new ConsoleText("Line 1"),
new ConsoleText("Line 2"),
new ConsoleText("Line 3"),
new ConsoleText("Line 4"),
new ConsoleText("Line 5")
);
viewport.Render();
// Alternatively through Fluent API:
Viewport fluentViewport = new Viewport(height: 10)
.Add(new ConsoleText("Line 1"))
.Add(new ConsoleText("Line 2"))
// ... 50+ more lines
.Add(new ConsoleText("Line 52"));
fluentViewport.Render(); // Initially shows lines 1-10
// User can scroll
fluentViewport.ScrollDown(3); // Now shows lines 4-13
fluentViewport.Render();
fluentViewport.ScrollUp(1); // Back to lines 3-12
fluentViewport.Render();
fluentViewport.ScrollToTop(); // Back to lines 1-10
fluentViewport.Render();
// Users can also interact with the viewport itself through up/down arrow keys:
fluenViewport.Interact();using ConsolePrism.Layout;
Column column = new(
gap: 2,
new Panel(title: "Left", content: new ConsoleText("A")),
new Panel(title: "Middle", content: new ConsoleText("B")),
new Panel(title: "Right", content: new ConsoleText("C"))
);
column.Render();
// Alternatively through Fluent API:
Column fluentColumn = new Column(gap: 2)
.Add(new Panel(title: "Left", content: new ConsoleText("A")))
.Add(new Panel(title: "Middle", content: new ConsoleText("B")))
.Add(new Panel(title: "Right", content: new ConsoleText("C")));
fluentColumn.Render();using ConsolePrism.Layout;
using ConsolePrism.Components;
Panel mainContent = new(
title: "Dashboard",
content: new ConsoleText("Welcome to the application!"),
horizontalPadding: 2
);
// Wrap the content in the AppShell
AppShell shell = new(
title: "MY AWESOME CLI",
content: mainContent,
leftFooter: "Status: Online",
rightFooter: "v1.0.0 | Press ESC to exit"
);
shell.Render();using ConsolePrism.Core;
// Positioning
ConsoleHelper.WriteCentered("Centered Title");
ConsoleHelper.WriteRight("Right-aligned", padding: 2);
ConsoleHelper.WriteAt("Positioned text", x: 10, y: 5);
// Cursor control
ConsoleHelper.HideCursor();
ConsoleHelper.MoveCursor(0, 10);
ConsoleHelper.ShowCursor();
// Drawing
ConsoleHelper.DrawHorizontalLine('โ');
ConsoleHelper.WriteEmptyLines(2);- NordTheme - Arctic blue tones with rounded borders
- MonochromeTheme - Grayscale for minimal or accessible output
- RetroTheme - Amber tones with ASCII borders
- MatrixTheme - Cascading greens against a dark background
- SunsetTheme - Cosy oranges, magenta and soft whites to evoke a twilight atmosphere
- SolarizedTheme - Warm amber and earthy tones with cool accent colours
- PastelTheme - Muted, light tones for a gentle visual experience
using ConsolePrism.Themes;
using ConsolePrism.Themes.Presets;
// Apply globally
Theme.Apply(NordTheme.Instance);
// Reset to default
Theme.Apply(Theme.Default);using ConsolePrism.Themes;
Theme myTheme = new()
{
Colors = new ColorScheme
{
Primary = ConsoleColor.Cyan,
Success = ConsoleColor.Green,
Error = ConsoleColor.Red,
Warning = ConsoleColor.Yellow,
Info = ConsoleColor.Blue,
Highlight = ConsoleColor.Magenta,
Muted = ConsoleColor.DarkGray,
MenuTitle = ConsoleColor.Cyan,
MenuOption = ConsoleColor.White,
MenuSelected = ConsoleColor.Green,
MenuBorder = ConsoleColor.DarkGray,
TableHeader = ConsoleColor.Cyan,
TableBorder = ConsoleColor.DarkGray,
TableData = ConsoleColor.White,
ProgressBarComplete = ConsoleColor.Green,
ProgressBarIncomplete = ConsoleColor.DarkGray,
ProgressBarText = ConsoleColor.White
},
Border = BorderStyle.Rounded
};
Theme.Apply(myTheme);using ConsolePrism.Core;
using ConsolePrism.Themes.Presets;
// Theme.Current is temporarily replaced for the duration of the block
using (new ConsoleContext(MonochromeTheme.Instance))
{
table.Render();
}
// Theme.Current is automatically restored hereTable table = new(headers, data)
{
Theme = RetroTheme.Instance
};
table.Render(); // uses RetroTheme regardless of Theme.Currentusing ConsolePrism.Themes;
// Built-in presets
BorderStyle.Single; // โโโ โ โโโ (default)
BorderStyle.Double; // โโโ โ โโโ
BorderStyle.Rounded; // โญโโฎ โ โฐโโฏ
BorderStyle.Ascii; // +-+ | +-+
// Custom border
Borderstyle custom = new()
{
TopLeft = 'โ', TopRight = 'โ',
BottomLeft = 'โ', BottomRight = 'โ',
Horizontal = 'โ', Vertical = 'โ',
Cross = 'โฌ',
TeeLeft = 'โ ', TeeRight = 'โฃ',
TeeTop = 'โฆ', TeeBottom = 'โฉ'
};ConsolePrism/
โโโ Interfaces/
โ โโโ IRenderable โ Anything that can render itself
โ โโโ IInteractable โ Components that accept user input
โ โโโ IComponent โ Base interface for all UI components
| โโโ IRenderer โ Output backend abstraction
โ
โโโ Themes/
โ โโโ ColorScheme โ Full color palette definition
โ โโโ BorderStyle โ Border character set definition
โ โโโ Theme โ Unified theme object (ColorScheme + BorderStyle)
โ โโโ Presets/
โ
โโโ Core/
โ โโโ ColorWriter โ Semantic colored text output
โ โโโ ConsoleHelper โ Cursor control, positioning, and drawing utilities
โ โโโ ConsoleContext โ Scoped theme switching via IDisposable
โ โโโ Rendering/
โ โโโ ConsoleRenderer โ Default implementation writing to Console
โ โโโ StringRenderer โ In-memory buffer for testing and layout buffering
โ
โโโ Components/
| โโโ ComponentBase โ Abstract base with theme resolution and renderer swapping
โ โโโ Menu โ Numbered, interactive, and bordered menu styles
โ โโโ Table โ Auto-sizing bordered table with text wrapping
| โโโ TableCell โ Cell content with optional colour
โ โโโ ProgressBar โ Static and in-place animated progress bars
โ โโโ Spinner โ Animated spinners for async operations
โ โโโ Notification โ Transient styled messages with optional auto-dismiss
| โโโ ConsoleText โ Simple text for use with the layout components
โ โโโ Prompt โ Styled input prompt with optional masked entry
โ
โโโ Layout/
โโโ Panel โ Bordered content container with title support
โโโ Row โ Vertical component stacking with optional spacing
โโโ Column โ Horizontal side-by-side component layout
โโโ AppShell โ Common application layout with header, footer, and main content
โโโ Viewport โ Scrollable content region with fixed visible height
- .NET 9.0 or .NET 10.0
- Windows, macOS, or Linux
- A terminal with a dark background is recommended for the best visual experience
See LICENCE for details. (MIT Licence)
Contributions are welcome! You can:
- Report bugs or request features via Issues
- Submit pull requests
- Suggest improvements to the API
- Propose new components, themes, or layout containers