# RazorConsole
> High-performance Blazor TUI framework, built on top of [Spectre.Console](https://spectreconsole.net).
---
# Document: Quick Start
### Quick Start Guide
Get up and running with RazorConsole in four straightforward steps.
#### Step 1 · Installation
Install the core package from NuGet:
```shell
dotnet add package RazorConsole.Core
```
#### Step 2 · Project Setup
Enable the Razor SDK so your Razor components compile correctly. Update your project file:
```xml
Exenet8.0enable
```
#### Step 3 · Build Your First Component
Create a `Counter.razor` component:
```razor
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Components.Web
@using RazorConsole.Components
Current count
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
```
Wire it up in `Program.cs`:
```csharp
using Microsoft.Extensions.Hosting;
using RazorConsole.Core;
IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args)
.UseRazorConsole();
IHost host = hostBuilder.Build();
await host.RunAsync();
```
#### Step 4 · Run the App
Build and run your console UI:
```shell
dotnet run
```

You should see an interactive counter in the terminal. Use **Tab** to traverse focusable elements and **Enter** or **Space** to trigger actions.
---
# Document: Built-in Components
# Built-in Components
RazorConsole ships with a library of Spectre.Console-powered components covering layout, input, display, and utility scenarios. You can combine them just like regular Razor components to build rich terminal experiences.
## Layout
| Component | Highlights |
| ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| [Align](https://razorconsole.github.io/RazorConsole/components/Align) | Centers or aligns child content horizontally/vertically with optional fixed width/height. |
| [Columns](https://razorconsole.github.io/RazorConsole/components/Columns) | Flows children left-to-right, optionally expanding to fill the console width. |
| [Rows](https://razorconsole.github.io/RazorConsole/components/Rows) | Stacks children vertically, great for wizard-style layouts. |
| [Grid](https://razorconsole.github.io/RazorConsole/components/Grid) | Builds a multi-column layout with configurable column count and width. |
| [Padder](https://razorconsole.github.io/RazorConsole/components/Padder) | Adds Spectre padding around nested content to create spacing. |
| [Scrollable](https://razorconsole.github.io/RazorConsole/components/Scrollable) | Renders a sliding window of items (`PageSize`) with built-in keyboard navigation (Arrow keys, PageUp/Down). |
```razor
```
## Input
| Component | Highlights |
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| [TextButton](https://razorconsole.github.io/RazorConsole/components/TextButton) | Focusable button with customizable colors and click handlers via `EventCallback`. |
| [TextInput](https://razorconsole.github.io/RazorConsole/components/TextInput) | Collects user input with placeholder, change handler, and optional password masking. |
| [Select](https://razorconsole.github.io/RazorConsole/components/Select) | Keyboard-driven dropdown with highlighted selection state and callbacks. |
```razor
```
## Display
| Component | Highlights |
| --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| [Markup](https://razorconsole.github.io/RazorConsole/components/Markup) | Renders Spectre markup with color, background, and text decoration support. |
| [Panel](https://razorconsole.github.io/RazorConsole/components/Panel) | Creates framed sections with optional title and border styling. |
| [Border](https://razorconsole.github.io/RazorConsole/components/Border) | Wraps child content in a configurable border and padding. |
| [BarChart](https://razorconsole.github.io/RazorConsole/components/BarChart) | Visualizes numeric data as horizontal bars with customizable styling, labels, and scaling. |
| [BreakdownChart](https://razorconsole.github.io/RazorConsole/components/BreakdownChart) | Displays proportional data segments (pie-style) with optional legends and percentage values. |
| [StepChart](https://razorconsole.github.io/RazorConsole/components/StepChart) | Plots discrete values over time using Unicode box-drawing characters and multiple series. |
| [Figlet](https://razorconsole.github.io/RazorConsole/components/Figlet) | Produces large ASCII headers using Figlet fonts. |
| [SyntaxHighlighter](https://razorconsole.github.io/RazorConsole/components/SyntaxHighlighter) | Displays colorized source code with optional line numbers. |
| [SpectreCanvas](https://razorconsole.github.io/RazorConsole/components/SpectreCanvas) | Provides a low-level pixel buffer for drawing custom graphics or pixel art. |
| [Markdown](https://razorconsole.github.io/RazorConsole/components/Markdown) | Renders Markdown text directly in the console. |
| [Table](https://razorconsole.github.io/RazorConsole/components/Table) | Converts semantic `
` markup into Spectre tables. |
```razor
```
## Utilities
| Component | Highlights |
| ------------------------------------------------------------------------- | -------------------------------------------------- |
| [Spinner](https://razorconsole.github.io/RazorConsole/components/Spinner) | Animated progress indicator with optional message. |
| [Newline](https://razorconsole.github.io/RazorConsole/components/Newline) | Emits an empty line to separate sections. |
```razor
```
## Tips
- All components can be composed within one another—wrap inputs inside `Panel`, place buttons in `Columns`, etc.
- Spectre colors map to `Spectre.Console.Color`; use `Color.Red`, `Color.Blue`, or RGB constructors for precise styling.
- Prefer `EventCallback` parameters for handlers so components remain async-friendly.
- Combine with RazorConsole focus management features to deliver intuitive keyboard navigation.
---
# Document: Hot Reload
### Hot Reload Support
Build, tweak, and iterate without leaving your running console app.
RazorConsole supports hot reload via its metadata update handler so UI changes are reflected instantly—no restart required.
#### How it works
1. Run your application with `dotnet watch`.
2. Update a Razor component.
3. Save the file.
4. Watch the running console UI refresh automatically.
```shell
dotnet watch run
```
> **Tip:** Hot reload shines for component tweaks. Certain structural changes may still need a full restart.
---
# Document: Routing
# Routing
This document explains how routing works in modern `RazorConsole` and how to use it.
---
## 1. Routing basics
Routing in Blazor maps URLs to _Razor components_.
Key pieces:
- `@page` directive – declares a route for a component.
- `` / `Routes.razor` – central router component that matches URLs to pages.
- `NavigationManager` – service for programmatic navigation.
---
## 2. The `@page` directive
Any Razor component (`.razor`) becomes routable when it has at least one `@page` directive:
```razor
@page "/"
@page "/home"
Home
```
- Each `@page` line defines a route template.
- A component can have multiple routes (e.g., an old and a new URL).
- Routes are relative to the app’s base URL `/`.
### Example from a simple page:
```razor
@page "/welcome"
Welcome!
Welcome to Blazor!
```
## 3. Route templates & parameters
### 3.1. Basic parameters
You can define route parameters in the template:
```razor
@page "/todos/{id:int}"
Todo @Id
@code {
[Parameter]
public int Id { get; set; }
}
```
- `{id:int}` – parameter name is `id`, with an `int` constraint.
- To get parameter from route use `[Parameter]` attribute.
### 3.2. Optional parameters
Optional parameters use `?` syntax:
```razor
@page "/products"
@page "/products/{category?}"
Products @Category
@code {
[Parameter]
public string? Category { get; set; }
}
```
`/products` and `/products/books` both resolve to the same component.
### 3.3. Multiple parameters
```razor
@page "/orders/{year:int}/{month:int}"
@code {
[Parameter]
public int Year { get; set; }
[Parameter]
public int Month { get; set; }
}
```
### 3.4. Catch-all parameters
Catch-all parameters capture the rest of the URL segment:
```razor
@page "/files/{*path}"
@code {
[Parameter]
public string? Path { get; set; }
}
```
Example URLs:
- `/files/readme.txt`
- `/files/images/logo.png`
## 4. Routing in `RazorConsole`
In the new Blazor Web App template, routing is configured by the Routes component.
Its as simple as in [web blazor](https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/routing?view=aspnetcore-10.0)
A typical `Routes.razor`
```razor
@using Microsoft.AspNetCore.Components.Routing
Sorry, there's nothing at this address.
```
Key points:
- `AppAssembly` - router scans this assembly to find components with `@page`.
- `` - renders the matched component.
- `DefaultLayout` - layout used when the component doesn’t specify its own.
- ``- content shown when no route matches.
## 5. Layouts and route rendering
Layouts are normal components that wrap pages. Common pattern:
```razor
@layout MainLayout
@page "/counter"
Counter
...
```
If no `@layout` is specified:
- The `DefaultLayout` from `RouteView` in `Routes.razor` is used.
## 6. Programmatic navigation with `NavigationManager`
Blazor exposes [`NavigationManager`](https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/routing?view=aspnetcore-10.0) for navigating in code-behind or services.
Inject it:
```razor
@inject NavigationManager Navigation
```
Basic usage:
```cs
Navigation.NavigateTo("/counter");
```
## 7. Unsupported features
Feel free to contribute
- `HeadOutlet` - there is no `head` in cli app.
- [Hash routing](https://developer.mozilla.org/en-US/docs/Glossary/Hash_routing)
- `NavLink`
## 8. Examples
[RazorConsole.Gallery](https://github.com/RazorConsole/RazorConsole/blob/main/src/RazorConsole.Gallery)
---
# Document: Native Ahead-of-Time Compilation
# Native AOT
This document explains how to use **Native Ahead-of-Time (AOT)** compilation with **RazorConsole** to build standalone, lightning-fast console applications.
> [!WARNING]
> Native AOT support in RazorConsole is currently **experimental**.
> While core features like routing and rendering are tested and working, you may encounter edge cases with third-party
> libraries or complex reflection scenarios. Please report any issues on [GitHub](https://github.com/RazorConsole/RazorConsole/issues/new?template=bug-report.yml).
---
## 1. What is Native AOT?
Native AOT compiles your .NET application directly into _native machine code_ like other compiled languages does, rather than Intermediate Language (IL) that requires a JIT compiler at runtime.
**Benefits for Console Apps:**
- **Instant Startup:** No JIT warm-up time.
- **Smaller Footprint:** No need to install the .NET Runtime on the target machine; the app is self-contained.
- **Single File:** The output is a single binary executable.
---
## 2. Prerequisites
To build Native AOT applications, you need platform-specific build tools installed on your development machine or CI environment.
Look at this article in [msdocs](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8).
---
## 3. How to Publish
To publish your application as a native executable, use the standard `dotnet publish` command with the `-p:PublishAot=true` property.
You **must** specify a Runtime Identifier (RID), as native code is platform-specific.
```bash
# Publish for Linux
dotnet publish -c Release -r linux-x64 -p:PublishAot=true
# Publish for Windows
dotnet publish -c Release -r win-x64 -p:PublishAot=true
# Publish for macOS (Apple Silicon)
dotnet publish -c Release -r osx-arm64 -p:PublishAot=true
```
The resulting binary will be located in `bin/Release/net8.0/{rid}/publish/`.
---
## 4. Known Warnings & Limitations
### 4.1. The `IL2104` Warning
During the build, you might see:
> `warning IL2104: Assembly 'Microsoft.AspNetCore.Components' produced trim warnings`
**Why this happens:** Blazor was designed for browser scenarios where the
full .NET runtime is available. Some internal Blazor APIs use reflection
patterns that the AOT analyzer cannot verify.
**Is it safe?** Yes, for RazorConsole use cases. We've tested core features
(routing, rendering, DI) and they work correctly. The warnings are about
unused code paths in Blazor's browser-specific features.
**Suppressing the warning:**
```xml
$(NoWarn);IL2104
```
**When to investigate:** If you're using advanced Blazor features beyond
basic component rendering, test thoroughly with AOT.
### 4.2. Routing and Pages
By default, the .NET AOT compiler trims unused code aggressively. Because the Router finds pages via reflection, the trimmer might accidentally remove your page components if they aren't directly referenced.
To ensure routing works correctly, you must prevent your application assembly from being trimmed. Add this to your project file (`.csproj`):
```xml
```
### 4.3. Reflection & Parameters
Native AOT aggressively trims unused code. Anonymous types rely on reflection
to read properties at runtime, and the trimmer may remove property metadata
if it cannot statically prove the properties are used.
**Avoid Anonymous Types for Parameters:**
```csharp
// Avoid this in AOT
// The trimmer may remove property metadata, causing runtime failures
var parameters = new { Title = "Hello", Count = 5 };
```
**Use Dictionary Instead:**
Explicitly using `Dictionary` ensures the AOT compiler preserves the data.
```csharp
// Preferred way for AOT
var parameters = new Dictionary
{
{ "Title", "Hello" },
{ "Count", 5 }
};
await renderer.RenderAsync(parameters);
```
### 4.4. What Works & What Doesn't
**✅ AOT-Compatible:**
- Razor component rendering
- Routing (`@page` directives)
- Dependency injection
- `System.Text.Json` (with source generators)
- LINQ (query syntax)
**⚠️ Requires Care:**
- Third-party libraries (check for `IsAotCompatible`)
- Custom reflection code
- Dynamic assembly loading
**❌ Not Supported:**
- `System.Reflection.Emit`
- C# dynamic keyword
---
## 5. Troubleshooting
### Build fails with `error MSB3073` or `link.exe` not found (Windows)
This usually means the C++ Build Tools are missing.
1. Open **Visual Studio Installer**.
2. Modify your installation.
3. Check **Desktop development with C++**.
### App crashes immediately (Segmentation Fault / MissingMethodException)
If your app uses third-party libraries that rely heavily on reflection (e.g., JSON serializers other than `System.Text.Json` source generator), they might be incompatible with AOT.
- Try enabling the AOT analysis warnings in your project to see potential issues:
```xml
true
```
---
## 6. Examples
You can see a working AOT setup in the [RazorConsole.Gallery](https://github.com/RazorConsole/RazorConsole/blob/main/src/RazorConsole.Gallery) project.
---
# Document: Custom Translators
### Custom Translators
RazorConsole converts Razor components into Spectre.Console renderables through a Virtual DOM (VDOM) translation pipeline. You can plug into that pipeline with custom translators to render bespoke elements.
#### Creating a translator
Implement the `IVdomElementTranslator` interface and translate nodes that match your criteria:
```csharp
using RazorConsole.Core.Rendering.Vdom;
using RazorConsole.Core.Vdom;
using Spectre.Console;
using Spectre.Console.Rendering;
public sealed class OverflowElementTranslator : IVdomElementTranslator
{
// Lower priority values are processed first (1-1000+)
public int Priority => 85;
public bool TryTranslate(
VNode node,
TranslationContext context,
out IRenderable? renderable)
{
renderable = null;
// Check for a div with an overflow attribute
if (node.Kind != VNodeKind.Element ||
!string.Equals(node.TagName, "div", StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (!node.Attributes.TryGetValue("data-overflow", out var overflowType))
{
return false;
}
if (!VdomSpectreTranslator.TryConvertChildrenToRenderables(
node.Children, context, out var children))
{
return false;
}
var content = VdomSpectreTranslator.ComposeChildContent(children);
renderable = overflowType?.ToLowerInvariant() switch
{
"ellipsis" => new Padder(content).Overflow(Overflow.Ellipsis),
"crop" => new Padder(content).Overflow(Overflow.Crop),
"fold" => new Padder(content).Overflow(Overflow.Fold),
_ => content
};
return true;
}
}
```
#### Registering the translator
```csharp
using Microsoft.Extensions.Hosting;
using RazorConsole.Core;
using RazorConsole.Core.Vdom;
IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args)
.UseRazorConsole(configure: config =>
{
config.ConfigureServices(services =>
{
services.AddVdomTranslator();
});
}
);
IHost host = hostBuilder.Build();
await host.RunAsync();
```
#### Using it in components
```razor
This text will be truncated with ellipsis if it's too long
```
For a deeper dive, read the [custom translators guide](https://github.com/RazorConsole/RazorConsole/blob/main/design-doc/custom-translators.md).
---
# Document: Absolute Positioning & Z-Index
# Absolute Positioning & Z-Index
This document explains how absolute positioning and layering work in `RazorConsole` and how to create complex layouts using the `absolute` coordinate system.
---
## 1. Positioning Basics
By default, elements in `RazorConsole` follow the **Normal Flow** (stacked vertically or horizontally depending on the container).
When you apply `position="absolute"`, the element is:
- **Removed from the normal flow**: It no longer takes up space in the layout, and other elements behave as if it isn't there.
- **Placed on an Overlay Layer**: It is rendered on top of the background content.
- **Positioned relative to the Document Root (Canvas)** or its nearest positioned ancestor.
---
## 2. Coordinate System
You can control the position of an absolute element using four attributes: `top`, `bottom`, `left`, and `right`.
| Attribute | Description |
| ------------ | -------------------------------------------------------- |
| **`top`** | Distance from the top edge of the document/ancestor. |
| **`left`** | Distance from the left edge of the document/ancestor. |
| **`bottom`** | Distance from the bottom edge of the **total document**. |
| **`right`** | Distance from the right edge of the **total document**. |
### 2.1. Stretching
If you provide both `left` and `right` , the element will **stretch** to fill the specified range.
`top` and `bottom` vertical stretching doesn't work, because of the current render system, that does not allow to set height directly.
```razor
```
> [!NOTE] Horizontal stretch will work correctly only with elements that allows to be expanded (like ``).
---
## 3. Hierarchical Positioning (Cumulative Offsets)
`RazorConsole` supports nested absolute positioning. If an `absolute` element is placed inside another `absolute` element, the child's `top` and `left` values are added to the parent's coordinates.
This is known as **Cumulative Offsets**. The formula for the final global position is:
### Example of nesting:
```razor
```
> [!NOTE] `bottom` and `right` always calculate their position relative to the **edges of the entire document (Canvas)**, regardless of nesting.
---
## 4. Z-Index and Layering
The `z-index` attribute determines the stacking order of elements that overlap.
- **Default value:** `0`.
- **Higher values:** Elements move "closer" to the user (rendered on top).
- **Lower/Negative values:** Elements move "further back".
```razor
Top Layer
Bottom Layer
```
In this example, the **Red Panel** will be rendered over the **Blue Panel** because it has a higher `z-index`, even though it starts earlier in the code.
---
## 5. Canvas Expansion
In `RazorConsole`, the "Document" (Canvas) is dynamic.
1. It starts with the size of the background content.
2. If an absolute element is placed outside these bounds (e.g., `top="50"` when the background only has 10 lines), the **Canvas automatically expands** with empty lines to accommodate the element.
---
## 6. Implementation Details
Absolute positioning is handled by the [`AbsolutePositionMiddleware`](https://github.com/LittleLittleCloud/RazorConsole/blob/main/src/RazorConsole.Core/Rendering/Translation/Translators/AbsolutePositionMiddleware.cs). It intercepts nodes with the `position="absolute"` attribute and moves them to a special `CollectedOverlays` list in the `TranslationContext`.
The final composition is performed by [`OverlayRenderable`](https://github.com/LittleLittleCloud/RazorConsole/blob/main/src/RazorConsole.Core/Renderables/OverlayRenderable.cs), which:
1. Renders the background.
2. Splits the output into a line-based `canvas`.
3. Handles `z-index` sorting before merging
4. Merges overlay segments into the canvas.
---
## 7. Unsupported Features
- **`position="relative"` or `position="fixed"`**: Currently, we have only `absolute` position or non-positioned elements in main flow.
- **Percentage units**: Only integer values (character units) are supported (e.g., `top="10%"` is not supported).
---
# Document: Keyboard Events
### Keyboard Events
Interactive experiences rely on keyboard input. RazorConsole exposes the familiar Blazor event model so you can respond to keystrokes just like you would on the web.
#### Custom key handling
```razor
@code {
private string message = "Press any key...";
private void HandleKeyPress(KeyboardEventArgs e)
{
message = $"You pressed: {e.Key}";
StateHasChanged();
}
}
```
#### Supported events
- `@onkeydown` — fires when a key is pressed.
- `@onkeyup` — fires when a key is released.
- `@onkeypress` — fires when a key is pressed and released.
---
# Document: Focus Management
# Focus Management
Console UIs need strong focus cues for keyboard navigation. RazorConsole provides a `FocusManager` that automatically tracks focusable elements and coordinates focus changes, making keyboard navigation predictable and accessible.
## Overview
The `FocusManager` is a singleton service that:
- Tracks all focusable elements in the virtual DOM
- Manages focus order and navigation
- Dispatches focus events (`onfocus`, `onfocusin`, `onfocusout`)
- Automatically refocuses when the DOM structure changes
- Provides programmatic control over focus
Focus management is handled automatically when you use RazorConsole's built-in components, but you can also control focus programmatically for advanced scenarios.
## Making Elements Focusable
Elements become focusable in two ways:
### 1. Using `data-focusable` Attribute
Set `data-focusable="true"` on any element to make it focusable:
```razor
```
### 2. Elements with Event Handlers
Elements with event handlers (like `@onclick`, `@onkeydown`) are automatically focusable:
```razor
```
### 3. Built-in Components
Built-in components like `TextInput` and `TextButton` are automatically focusable:
```razor
```
## Setting Focus Order
Use the `FocusOrder` parameter on built-in components to control tab order:
```razor
```
For custom elements, use the `data-focus-order` attribute:
```razor
```
## Keyboard Navigation
Users can navigate between focusable elements using:
- **Tab** - Move focus to the next element
- **Shift + Tab** - Move focus to the previous element
Navigation wraps around: when reaching the last element, Tab moves to the first, and vice versa.
## Programmatic Focus Control
You can programmatically control focus by injecting `FocusManager` into your components.
### Injecting FocusManager
```razor
@using RazorConsole.Core.Focus
@inject FocusManager FocusManager
@code {
// Use FocusManager methods here
}
```
### Available Methods
#### FocusAsync(string key)
Focus a specific element by its key:
```razor
@using RazorConsole.Core.Focus
@inject FocusManager FocusManager
@code {
private string username = string.Empty;
private string password = string.Empty;
private async Task FocusUsername()
{
await FocusManager.FocusAsync("username-input");
}
}
```
#### FocusNextAsync() and FocusPreviousAsync()
Move focus programmatically:
```razor
@using RazorConsole.Core.Focus
@inject FocusManager FocusManager
@code {
private string field1 = string.Empty;
private string field2 = string.Empty;
private string field3 = string.Empty;
private async Task MoveToNext()
{
await FocusManager.FocusNextAsync();
}
private async Task MoveToPrevious()
{
await FocusManager.FocusPreviousAsync();
}
}
```
#### Checking Focus State
Check if an element is currently focused:
```razor
@using RazorConsole.Core.Focus
@inject FocusManager FocusManager
@code {
// Check current focus
private string? CurrentFocus => FocusManager.CurrentFocusKey;
// Check if manager has any focusable elements
private bool HasFocusables => FocusManager.HasFocusables;
}
```
### Subscribing to Focus Changes
Subscribe to the `FocusChanged` event to react to focus changes:
```razor
@using RazorConsole.Core.Focus
@inject FocusManager FocusManager
@implements IDisposable
@code {
private string? currentFocus;
protected override void OnInitialized()
{
FocusManager.FocusChanged += OnFocusChanged;
currentFocus = FocusManager.CurrentFocusKey;
}
private void OnFocusChanged(object? sender, FocusChangedEventArgs e)
{
currentFocus = e.Key;
StateHasChanged();
}
public void Dispose()
{
FocusManager.FocusChanged -= OnFocusChanged;
}
}
```
## Responding to Focus Events
Elements can respond to focus changes using event handlers:
### onfocus
Fired when an element receives focus:
```razor
@code {
private string message = "Not focused";
private void OnFocus(FocusEventArgs e)
{
message = "Focused!";
StateHasChanged();
}
}
```
### onfocusin
Similar to `onfocus`, but bubbles up through parent elements:
```razor
@code {
private void OnFocusIn(FocusEventArgs e)
{
// Fired when child receives focus
}
}
```
### onfocusout
Fired when an element loses focus:
```razor
@code {
private string message = "Not focused";
private void OnFocus(FocusEventArgs e)
{
message = "Focused!";
StateHasChanged();
}
private void OnFocusOut(FocusEventArgs e)
{
message = "Focus lost";
StateHasChanged();
}
}
```
## Focus Sessions
Focus management operates within a session that tracks the current render context. Sessions are automatically managed by RazorConsole when your application starts. The `FocusManager`:
- Automatically selects the first focusable element when a session begins
- Maintains focus state across re-renders
- Automatically refocuses when the currently focused element is removed from the DOM
- Clears focus when all focusable elements are removed
## Navigation Between Pages
When navigating between pages or components, focus management automatically adapts:
1. **New Page Loads**: The first focusable element is automatically focused
2. **Component Changes**: Focus is maintained if the same element exists in the new view
3. **Element Removal**: If the focused element is removed, focus moves to the next available element
Example with navigation:
```razor
@using RazorConsole.Core.Focus
@inject FocusManager FocusManager
@inject NavigationManager Navigation
@code {
private async Task NavigateToLogin()
{
Navigation.NavigateTo("/login");
// Focus will automatically move to the first focusable element
// on the login page when it renders
}
}
```
## Complete Example
Here's a complete example demonstrating focus management:
```razor
@using RazorConsole.Core.Focus
@using RazorConsole.Components
@inject FocusManager FocusManager
@implements IDisposable
@code {
private string value1 = string.Empty;
private string value2 = string.Empty;
private string value3 = string.Empty;
private string? currentFocus;
protected override void OnInitialized()
{
FocusManager.FocusChanged += OnFocusChanged;
currentFocus = FocusManager.CurrentFocusKey;
}
private void OnFocusChanged(object? sender, FocusChangedEventArgs e)
{
currentFocus = e.Key;
StateHasChanged();
}
private async Task FocusFirst()
{
await FocusManager.FocusAsync("input1");
}
private async Task FocusSecond()
{
await FocusManager.FocusAsync("input2");
}
private async Task FocusThird()
{
await FocusManager.FocusAsync("input3");
}
private async Task FocusNext()
{
await FocusManager.FocusNextAsync();
}
private async Task FocusPrevious()
{
await FocusManager.FocusPreviousAsync();
}
public void Dispose()
{
FocusManager.FocusChanged -= OnFocusChanged;
}
}
```
## Best Practices
1. **Always use `@key` attributes** on focusable elements to ensure stable focus keys
2. **Set `FocusOrder`** on form elements to create a logical tab sequence
3. **Handle focus events** to provide visual feedback when elements receive/lose focus
4. **Use `FocusManager` programmatically** for complex navigation scenarios or when focus needs to change based on application logic
5. **Clean up event subscriptions** by implementing `IDisposable` and unsubscribing from `FocusChanged` events
6. **Test keyboard navigation** to ensure your UI is accessible and intuitive
---
# Document: VDom Tree Debugging
### VDom Tree Visualization
Debug and inspect the Virtual DOM structure of your RazorConsole components with the built-in VDom tree printer.
#### Overview
RazorConsole uses a Virtual DOM (VDOM) to efficiently render Razor components to the console. When debugging complex component hierarchies or investigating rendering issues, you can enable the VDom tree printer to visualize the internal structure.
#### How to Enable
Set the `RC_PRINT_VDOM_TREE` environment variable to `true` before running your application:
**On Windows (PowerShell):**
```shell
$env:RC_PRINT_VDOM_TREE="true"
dotnet run
```
**On Linux/macOS:**
```shell
RC_PRINT_VDOM_TREE=true dotnet run
```
**Or inline:**
```shell
RC_PRINT_VDOM_TREE=true dotnet watch run
```
#### What You'll See
When enabled, the tree printer displays each frame's VDOM structure in a panel, showing:
- **Node hierarchy** - Visual tree structure with indentation
- **Node types** - Element, Text, Component, or Region
- **Element details** - Tag names, keys, IDs, and text content
- **Attributes** - All data attributes attached to nodes
- **Events** - Registered event handlers (onclick, onfocus, etc.)
**Example output:**
```
Frame 1
┌─────────────────────────────────────────┐
│ • Element div key=root-key text='...' │
│ v-id=a3f2 attrs[data-rows=true] │
│ ├── Element span key=first │
│ │ text='First Item' v-id=b7c4 │
│ │ attrs[data-focusable=true] │
│ │ events[onfocus, onfocusin] │
│ └── Element span key=second │
│ text='Second Item' v-id=c1d8 │
│ attrs[data-focusable=true] │
│ events[onfocus, onfocusin] │
└─────────────────────────────────────────┘
```
#### Frame History
The tree printer accumulates frames as your application runs, allowing you to see how the VDOM evolves over time. Each panel represents a snapshot of the VDOM at a specific render cycle.
> **Note:** This feature has a performance impact and is intended for development and debugging only. Don't enable it in production environments.
#### Technical Details
The VDom tree printer is implemented as an `IVdomElementTranslator` with priority 0 (highest priority). When enabled, it intercepts the translation process and generates a text representation of the entire VDOM tree before passing through to the standard rendering pipeline.
For more information on custom translators, see the [Custom Translators](/docs#custom-translators) guide.
---
# Document: Component Gallery
### Interactive Component Gallery
Explore every RazorConsole component in a live playground.
```shell
dotnet tool install --global RazorConsole.Gallery
```
```shell
razorconsole-gallery
```
The gallery lets you experiment with layouts, inputs, and utilities before pulling them into your own app.
---
# Component: Align
Wraps child content in an alignment container.
### Parameters:
| Name | Type | Default | Description |
| ------------ | ---------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------- |
| ChildContent | Microsoft.AspNetCore.Components.RenderFragment | - | Aligns content horizontally and vertically within a container using Spectre.Console's Align renderable. |
| Height | int? | - | Height of the alignment container in characters. If `null`, automatically determined by content. |
| Horizontal | HorizontalAlignment | - | Horizontal alignment of the content. Default is Left. |
| Vertical | VerticalAlignment | - | Vertical alignment of the content. Default is Top. |
| Width | int? | - | Width of the alignment container in characters. If `null`, automatically determined by content. |
### Usage Example (Align_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
````
---
# Component: Border
Creates a bordered panel around its children.
### Parameters:
| Name | Type | Default | Description |
| ------------ | ---------------------------------------------- | ------- | -------------------------------------------------------------------------------------- |
| BorderColor | Color? | - | Color of the border. If `null`, uses default console color. |
| BoxBorder | BoxBorder | - | Style of the border. Default is Rounded. See BoxBorder for available styles. |
| ChildContent | Microsoft.AspNetCore.Components.RenderFragment | - | Renders a simple border around content without a title (simplified wrapper for Panel). |
| Padding | Padding | - | Padding inside the border as (left, top, right, bottom). Default is (0, 0, 0, 0). |
### Usage Example (Border_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
````
---
# Component: BarChart
Renders a horizontal bar chart with optional label, colors and value display.
### Parameters:
| Name | Type | Default | Description |
| --------------- | ------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| BarChartItems | List | - | Renders a bar chart using Spectre.Console's BarChart renderable. |
| Culture | CultureInfo? | - | CultureInfo to use when rendering values. Default is CurrentCulture. |
| Label | string? | - | Label (title) displayed above the bar chart. |
| LabelAlignment | Justify? | - | Alignment of the chart label. Options: Left, Center, Right. |
| LabelBackground | Color? | - | Background color of the chart label. Default is Plain background (transparent). |
| LabelDecoration | Decoration? | - | Text decoration for the chart label (bold, italic, underline, etc.). Default is None. |
| LabelForeground | Color? | - | Foreground (text) color of the chart label. Default is Plain foreground. |
| MaxValue | double? | - | Fixed maximum value for scaling bars. When set, bars scale relative to this value instead of the largest data point. Example: `MaxValue = 100` creates a progress chart (0–100%). |
| ShowValues | bool | - | Whether numeric values should be displayed next to each bar. Default is `false`. |
| Width | int? | - | Width of the bar chart in characters. If `null`, uses available console width. |
### Usage Example (BarChart_1.razor):
````razor
@using RazorConsole.Components
@using System.Globalization
@using Spectre.Console
@code {
private List SalesData => new()
{
new BarChartItem("Jan", 65.2, Color.FromHex("29B8DB")),
new BarChartItem("Feb", 78.9, Color.FromHex("0DBC79")),
new BarChartItem("Mar", 91.5, Color.FromHex("F5F543"))
};
}
````
---
# Component: BreakdownChart
Displays a breakdown chart showing proportional data.
### Parameters:
| Name | Type | Default | Description |
| ----------------------- | -------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ |
| BreakdownChartItems | System.Collections.Generic.List{Spectre.Console.IBreakdownChartItem} | - | Renders a breakdown chart using Spectre.Console's BreakdownChart renderable. |
| Compact | System.Boolean | - | Whether the chart and tags should be rendered in compact mode. Default is `false`. |
| Culture | System.Globalization.CultureInfo | - | CultureInfo to use when rendering values. Default is CurrentCulture. |
| Expand | System.Boolean | - | Whether the chart should expand to available space. When `false`, width is automatically calculated. Default is `false`. |
| ShowTagValues | System.Boolean | - | Whether to show tag values. Default is `false`. |
| ShowTagValuesPercentage | System.Boolean | - | Whether to show tag values with percentage. Default is `false`. |
| ShowTags | System.Boolean | - | Whether to show tags. Default is `false`. |
| ValueColor | System.Nullable{Spectre.Console.Color} | - | Color in which the values will be shown. If `null`, uses default color. |
| Width | System.Nullable{System.Int32} | - | Width of the breakdown chart in characters. If `null`, automatically calculated. |
### Usage Example (BreakdownChart_1.razor):
````razor
@using RazorConsole.Components
@using System.Globalization
@using Spectre.Console
@code {
private List Expenses => new()
{
new BreakdownChartItem("Food", 3200, Color.FromHex("F5F543")),
new BreakdownChartItem("Transport", 1800, Color.FromHex("3B8EEA")),
new BreakdownChartItem("Utilities", 2500, Color.FromHex("CD3131")),
new BreakdownChartItem("Fun", 1400, Color.FromHex("0DBC79")),
new BreakdownChartItem("Other", 1100, Color.FromHex("666666"))
};
}
````
---
# Component: Columns
Arranges children in columns.
### Parameters:
| Name | Type | Default | Description |
| ------------ | ---------------------------------------------- | ------- | ------------------------------------------------------------------------------------- |
| ChildContent | Microsoft.AspNetCore.Components.RenderFragment | - | Content to arrange in columns. |
| Expand | System.Boolean | - | Whether columns should expand to fill available horizontal space. Default is `false`. |
### Usage Example (Columns_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
````
---
# Component: Figlet
Renders ASCII art text.
### Parameters:
| Name | Type | Default | Description |
| ------- | ------------- | ------- | ----------------------------------------------------------------------- |
| Color | Color? | - | Color of the FIGlet text. Default is Default (console's default color). |
| Content | string? | - | Text content to render as FIGlet ASCII art. |
| Font | System.String | - | Custom FIGlet font name or path to .flf file |
| Justify | Justify? | - | Horizontal alignment of the FIGlet text. Default is Center. |
### Usage Example (Figlet_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
````
---
# Component: Grid
Arranges children in a grid layout.
### Parameters:
| Name | Type | Default | Description |
| ------------ | ---------------------------------------------- | ------- | -------------------------------------------------------------------------------- |
| ChildContent | Microsoft.AspNetCore.Components.RenderFragment | - | Arranges content in a multi-column grid using Spectre.Console's Grid renderable. |
| Columns | System.Int32 | - | Number of columns in the grid. Default is 2. Must be positive. |
| Expand | System.Boolean | - | Whether the grid should expand to fill available space. Default is `false`. |
| Width | System.Nullable{System.Int32} | - | Width of the grid in characters. If `null`, automatically determined by content. |
### Usage Example (Grid_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
````
---
# Component: ModalWindow
Renders a modal in a dialog.
### Parameters:
| Name | Type | Default | Description |
| -------------------- | --------------------------------------------------------------------------- | ------- | --------------------------------------------------------- |
| AdditionalAttributes | System.Collections.Generic.IReadOnlyDictionary{System.String,System.Object} | - | Additional HTML attributes to apply to the table element. |
| ChildContent | Microsoft.AspNetCore.Components.RenderFragment | - | |
| IsOpened | System.Boolean | - | Parameter that determines visibility of modal window |
### Usage Example (ModalWindow_1.razor):
````razor
@using RazorConsole.Components
@using Spectre.Console
@using Panel = RazorConsole.Components.Panel
@if (!_isOpened)
{
}
@code {
private bool _isOpened = true;
private Color _currentColor = Color.Orange1;
private void CloseModal()
{
_isOpened = false;
StateHasChanged();
}
private void OpenModal()
{
_isOpened = true;
StateHasChanged();
}
private void ChangeColor()
{
_currentColor = _currentColor == Color.Orange1 ? Color.Red3 : Color.Orange1;
StateHasChanged();
}
}
````
---
# Component: Markdown
Renders markdown content.
### Parameters:
| Name | Type | Default | Description |
| ------- | ------------- | ------- | -------------------------------------------------------------- |
| Content | System.String | - | Markdown content to render. Supports standard Markdown syntax. |
### Usage Example (Markdown_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
@code {
private static string markdownText => @"# Welcome to Markdown
This is a **bold** statement and this is *italic*. You can also have `inline code`.
## Features
Here's what you can do with markdown:
- Create bullet lists
- With multiple items
- Like this one
### Ordered Lists
1. First item
2. Second item
3. Third item
### Nested Lists
- Top level item A
- Child item A.1
- Grandchild item `A.1.a`
- Child item A.2
### Code Blocks
```csharp
public class HelloWorld
{
public static void Main()
{
Console.WriteLine(""Hello, World!"");
}
}
```
```python
def greet(name):
print(f""Hello, {name}!"")
greet(""World"")
```
### Quotes
> This is a quote block.
> It can span multiple lines.
### Tables
| Feature | Supported | Description |
|---------|-----------|-------------|
| Basic Tables | ✓ | Simple table formatting |
| Column Alignment | ✓ | Left, center, right alignment |
| Complex Content | ✓ | Code, links, and formatting in cells |
Here's a more detailed table:
| Language | Extension | Example Code | Performance |
|:---------|:---------:|:-------------|------------:|
| C# | `.cs` | `Console.WriteLine(""Hello"");` | Fast |
| Python | `.py` | `print(""Hello"")` | Medium |
| JavaScript | `.js` | `console.log(""Hello"");` | Variable |
---
That's a horizontal rule above!
".Trim();
}
````
---
# Component: Markup
Renders styled text with markup.
### Parameters:
| Name | Type | Default | Description |
| ---------- | ----------- | ------- | ------------------------------------------------------------------------------------------------------ |
| Background | Color? | - | Background color. Default is Plain background. |
| Content | string? | - | Text content to render. Content is automatically escaped to prevent markup interpretation. |
| Decoration | Decoration? | - | Text decoration (bold, italic, underline, etc.). Default is None. Combine decorations with bitwise OR. |
| Foreground | Color? | - | Foreground (text) color. Default is Plain foreground. |
| link | string? | - | Optional hyperlink URL. When specified, text renders as a clickable link in supported terminals. |
### Usage Example (Markup_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
````
---
# Component: Padder
Adds padding around its children.
### Parameters:
| Name | Type | Default | Description |
| ------------ | ---------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ChildContent | Microsoft.AspNetCore.Components.RenderFragment | - | Content to which padding will be applied. |
| Padding | Spectre.Console.Padding | - | Padding to apply as (left, top, right, bottom) in characters. Default is (0, 0, 0, 0). Example: `new Padding(2, 1, 2, 1)` adds 2 characters horizontally and 1 line vertically. |
### Usage Example (Padder_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
````
---
# Component: Panel
Creates a bordered panel with optional title.
### Parameters:
| Name | Type | Default | Description |
| ------------ | ---------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------- |
| Border | BoxBorder | - | Style of the panel border. See BoxBorder for available styles like Rounded, Square, and Double. |
| BorderColor | Color? | - | Color of the panel border. If `null`, uses default console color. |
| ChildContent | Microsoft.AspNetCore.Components.RenderFragment | - | Renders a panel with optional title, border, and padding using Spectre.Console's Panel renderable. |
| Expand | bool | - | Whether the panel should expand to fill available space. Default is `false`. |
| Height | int? | - | Height of the panel in lines. If `null` or less than 1, height is automatically determined by content. |
| Padding | Padding? | - | Padding inside the panel border as (left, top, right, bottom). If `null`, no padding is applied. |
| Title | string? | - | Title text displayed at the top of the panel border. If `null` or empty, no title is shown. |
| TitleColor | Color? | - | Color of the panel title. If `null`, uses default console color. |
| Width | int? | - | Width of the panel in characters. If `null` or less than 1, width is automatically determined by content. |
### Usage Example (Panel_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
````
---
# Component: Rows
Arranges children in rows.
### Parameters:
| Name | Type | Default | Description |
| ------------ | ---------------------------------------------- | ------- | -------------------------------------------------------------------------- |
| ChildContent | Microsoft.AspNetCore.Components.RenderFragment | - | Content to arrange in rows. |
| Expand | System.Boolean | - | Arranges content in vertical rows using Spectre.Console's Rows renderable. |
### Usage Example (Rows_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
````
---
# Component: Scrollable
Provides scrollable content area.
### Parameters:
| Name | Type | Default | Description |
| ------------------- | ----------------------------------------------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------- |
| ChildContent | Microsoft.AspNetCore.Components.RenderFragment{RazorConsole.Components.Scrollable`1.ScrollContext{{TItem}}} | - | Child content template that receives the visible items and scroll context. |
| IsScrollbarEmbedded | System.Boolean | - | Flag that determines will scrollbar be embedded or not. |
| Items | System.Collections.Generic.IReadOnlyList{{TItem}} | - | Provides scrollable navigation through a list of items with keyboard support. |
| PageSize | System.Int32 | - | Number of items visible at one time (page size). |
| ScrollOffset | System.Int32 | - | Current scroll offset (index of the first visible item). |
| ScrollOffsetChanged | Microsoft.AspNetCore.Components.EventCallback{System.Int32} | - | Event callback invoked when the scroll offset changes. |
| Scrollbar | RazorConsole.Core.Rendering.ScrollbarSettings | - | Scrollbar settings. If provided, the scrollbar is enabled. |
### Usage Example (Scrollable_1.razor):
````razor
@using Microsoft.AspNetCore.Components.Web
@using Spectre.Console
@using RazorConsole.Components
NLetter
@foreach (var item in context)
{
}
@*Spaces beteween panels*@
NLetter
@foreach (var item in context)
{
}
@foreach (var item in context)
{
}
@foreach (var item in context)
{
}
@code {
private Color _tableColor = Color.White;
record Item(int Number, string Letter, Color Color);
private IReadOnlyList<(int Number, string Letter, Color Color)> GetAlphabetData()
{
return
[
(1, "A", Color.Yellow),
(2, "B", Color.Red),
(3, "C", Color.Aqua),
(4, "D", Color.Orange1),
(5, "E", Color.Chartreuse1),
(6, "F", Color.Magenta1),
(7, "G", Color.Green3),
(8, "H", Color.Blue),
(9, "I", Color.Purple),
(10, "J", Color.Gold1),
(11, "K", Color.Turquoise2),
(12, "L", Color.HotPink),
(13, "M", Color.Lime),
(14, "N", Color.LightCoral),
(15, "O", Color.SkyBlue1)
];
}
private void OnFocusTable(FocusEventArgs e)
{
_tableColor = Color.Aqua;
}
private void OnFocusOutTable(FocusEventArgs e)
{
_tableColor = Color.White;
}
}
````
---
# Component: ViewHeightScrollable
Provides scrollable content area that scrolls through physical lines of any content. Has all functionalities of default Scrollable.
### Parameters:
| Name | Type | Default | Description |
| ------------------- | ---------------------------------------------------------------------------------------------------------- | ------- | ---------------------------------------------------------- |
| ChildContent | Microsoft.AspNetCore.Components.RenderFragment{RazorConsole.Components.ViewHeightScrollable.ScrollContext} | - | |
| IsScrollbarEmbedded | System.Boolean | - | Flag that determines will scrollbar be embedded or not. |
| LinesToRender | System.Int32 | - | Number of lines visible at one time. |
| ScrollOffset | System.Int32 | - | Current scroll offset (index of the first visible line). |
| ScrollOffsetChanged | Microsoft.AspNetCore.Components.EventCallback{System.Int32} | - | Event callback invoked when the scroll offset changes. |
| Scrollbar | RazorConsole.Core.Rendering.ScrollbarSettings | - | Scrollbar settings. If provided, the scrollbar is enabled. |
### Usage Example (ViewHeightScrollable_1.razor):
````razor
@using RazorConsole.Components
@using Spectre.Console
@using Markup = RazorConsole.Components.Markup
@using Panel = RazorConsole.Components.Panel
@code {
private readonly string _largeText =@"
#### Counter.razor
```razor
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Components.Web
@using RazorConsole.Components
Current count
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
```
#### Program.cs
```csharp
using Microsoft.Extensions.Hosting;
using RazorConsole.Core;
IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args)
.UseRazorConsole();
IHost host = hostBuilder.Build();
await host.RunAsync();
```
".Trim();
}
````
---
# Component: Select
Interactive dropdown for choosing a value with keyboard navigation.
### Parameters:
| Name | Type | Default | Description |
| ------------------------ | --------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------ |
| AdditionalAttributes | System.Collections.Generic.IReadOnlyDictionary{System.String,System.Object} | - | Additional attributes to apply to the root element. |
| Comparer | System.Collections.Generic.IEqualityComparer{{TItem}} | - | Custom comparer for items in the list. Default is object.Equals() |
| Expand | System.Boolean | - | Expands the rows layout to fill available space when true. |
| FocusedValue | {TItem} | - | Currently highlighted option during keyboard navigation (may differ from committed Value). |
| FocusedValueChanged | Microsoft.AspNetCore.Components.EventCallback{{TItem}} | - | Event raised when the focused option changes. |
| Formatter | System.Func{{TItem},System.String} | - | Custom formatter for the items in the list. Default is object.ToString() |
| IsFocused | System.Boolean | - | Indicates whether the select currently has focus. |
| IsFocusedChanged | Microsoft.AspNetCore.Components.EventCallback{System.Boolean} | - | Event raised when the focus state changes. |
| OptionDecoration | Spectre.Console.Decoration | - | Text decoration for non-focused options. |
| OptionForeground | Spectre.Console.Color | - | Foreground color for non-focused options. |
| Options | {TItem}[] | - | Available options rendered by the select. |
| SelectedIndicator | System.Char | - | Character used to indicate the focused option. |
| SelectedOptionDecoration | Spectre.Console.Decoration | - | Text decoration for the focused option. |
| SelectedOptionForeground | Spectre.Console.Color | - | Foreground color for the focused option. |
| UnselectedIndicator | System.Char | - | Character used to indicate non-focused options. |
| Value | {TItem} | - | Currently committed option value. |
| ValueChanged | Microsoft.AspNetCore.Components.EventCallback{{TItem}} | - | Event raised when the committed value changes. |
### Usage Example (Select_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
@* add helper text *@
@code {
private string[] options = new[] { "Option 1", "Option 2", "Option 3" };
private string? selectedValue;
private string? focusedValue;
}
````
---
# Component: StepChart
Renders a terminal step chart using Unicode box-drawing characters. Perfect for displaying discrete value changes over time or categories.
### Parameters:
| Name | Type | Default | Description |
| ----------- | ------------------------------------------------------------------------------ | ------- | --------------------------------------------------------------------------- |
| AxesColor | Spectre.Console.Color | - | Color of the axes lines and tick marks. |
| Height | System.Int32 | - | Height of the chart in terminal rows (excluding title and axes if shown). |
| LabelsColor | Spectre.Console.Color | - | Color of the numeric labels on X and Y axes. |
| Series | System.Collections.Generic.List{RazorConsole.Components.StepChart.ChartSeries} | - | Collection of data series to display on the chart. |
| ShowAxes | System.Boolean | - | Determines whether coordinate axes and value labels are rendered. |
| Title | System.String | - | Optional chart title displayed above the plot area. |
| TitleColor | Spectre.Console.Color | - | Color of the chart title text. |
| Width | System.Int32 | - | Width of the chart in terminal columns (excluding title and axes if shown). |
### Usage Example (StepChart_1.razor):
````razor
@using RazorConsole.Components
@using Spectre.Console
@code{
private List GenerateChartSeries()
{
return
[
new(Color.FromHex("0DBC79"), [new(1, 4), new(2, 5), new(3, 5), new(4, 4), new(5, 5), new(6, 6), new(7, 7), new(8, 8)]),
new(Color.FromHex("3B8EEA"), [new(1, 2), new(2, 2), new(3, 2), new(4, 3), new(5, 3), new(6, 4), new(7, 5), new(8, 6)]),
new(Color.FromHex("fc034e"), [new(1, 0), new(2, 0), new(3, 0), new(4, 1), new(5, 2), new(6, 2), new(7, 2), new(8, 3)])
];
}
}
````
---
# Component: SyntaxHighlighter
Renders highlighted code blocks with SyntaxHighlightingService.
### Parameters:
| Name | Type | Default | Description |
| -------------------- | --------------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| AdditionalAttributes | System.Collections.Generic.IReadOnlyDictionary{System.String,System.Object} | - | Additional HTML attributes for the syntax highlighter element. |
| Code | System.String | - | Source code to highlight. |
| Language | System.String | - | Programming language of the code. If `null`, attempts automatic detection. Supported: "csharp", "javascript", "python", "sql", etc. |
| Options | RazorConsole.Core.Rendering.Syntax.SyntaxOptions | - | Additional syntax highlighting options. If `null`, uses Default. |
| ShowLineNumbers | System.Boolean | - | Whether line numbers should be displayed. Default is `false`. |
| TabWidth | System.Nullable{System.Int32} | - | Width of tab characters in spaces. When specified and greater than 0, overrides tab width in Options. |
| Theme | System.String | - | Color theme for syntax highlighting. If `null`, uses default theme. |
### Usage Example (SyntaxHighlighter_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
@code {
private string codeSnippet = @"
public class HelloWorld
{
public void SayHello()
{
Console.WriteLine(""Hello, World!"");
}
}
".Trim();
}
````
---
# Component: Spinner
Shows a Spectre spinner with optional message.
### Parameters:
| Name | Type | Default | Description |
| ----------- | ----------------------- | ------- | ----------------------------------------------------------------------------------------- |
| AutoDismiss | System.Boolean | - | Whether the spinner should automatically dismiss when complete. Default is `false`. |
| Message | System.String | - | Message displayed next to the spinner. If `null` or empty, no message is shown. |
| SpinnerName | System.String | - | Name of the spinner to use (alternative to SpinnerType). Takes precedence when specified. |
| SpinnerType | Spectre.Console.Spinner | - | Type of spinner animation. Default is Dots. See Known for all available styles. |
| Style | System.String | - | Spectre.Console style markup to apply. If `null`, uses default style. |
### Usage Example (Spinner_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
````
---
# Component: SpectreCanvas
Renders an array of pixels with different colors.
### Parameters:
| Name | Type | Default | Description |
| ------------ | -------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| CanvasHeight | System.Int32 | - | Height of the canvas in pixels. |
| CanvasWidth | System.Int32 | - | Width of the canvas in pixels. |
| MaxWidth | System.Nullable{System.Int32} | - | Maximum width of the rendered canvas in console characters. If `null`, no constraint is applied. |
| PixelWidth | System.Int32 | - | Width of each pixel when rendered. Default is 2 characters, creating more square-looking pixels. |
| Pixels | System.ValueTuple{System.Int32,System.Int32,Spectre.Console.Color}[] | - | Renders a pixel-based canvas for drawing graphics in the console using Spectre.Console's Canvas renderable. |
| Scale | System.Boolean | - | Whether the canvas should automatically scale to fit the console. Default is `false`. |
### Usage Example (SpectreCanvas_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
@code {
private const int Width = 16;
private const int Height = 16;
private (int x, int y, Color color)[] Pixels { get; set; } = [];
protected override void OnInitialized()
{
var pixels = new List<(int, int, Color)>();
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
// 8x8 board, 2x2 pixels per square
int boardX = x / 2;
int boardY = y / 2;
bool isDark = (boardX + boardY) % 2 == 1;
var color = isDark ? Color.Black : Color.White;
pixels.Add((x, y, color));
}
}
Pixels = pixels.ToArray();
}
}
````
---
# Component: Newline
Emits a single line break. No parameters.
### Usage Example (Newline_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
````
---
# Component: Table
Renders a data table.
### Parameters:
| Name | Type | Default | Description |
| -------------------- | --------------------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------- |
| AdditionalAttributes | System.Collections.Generic.IReadOnlyDictionary{System.String,System.Object} | - | Additional HTML attributes to apply to the table element. |
| Border | Spectre.Console.TableBorder | - | Style of the table border. See TableBorder for available styles like Rounded, Square, and Minimal. |
| BorderColor | Spectre.Console.Color | - | Color of the table border. Default is White. |
| ChildContent | Microsoft.AspNetCore.Components.RenderFragment | - | Renders a formatted table using Spectre.Console's Table renderable. |
| Expand | System.Boolean | - | Whether the table should expand to fill available space. Default is `false`. |
| ShowHeaders | System.Boolean | - | Whether table headers should be displayed. Default is `true`. |
| Title | System.String | - | Title displayed above the table. If `null` or empty, no title is shown. |
| Width | System.Nullable{System.Int32} | - | Width of the table in characters. If `null` or less than 1, automatically determined by content. |
### Usage Example (Table_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
Name
Value
````
---
# Component: TextInput
Single-line text input field.
### Parameters:
| Name | Type | Default | Description |
| --------------------- | ------------------------------------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
| AdditionalAttributes | System.Collections.Generic.IReadOnlyDictionary{System.String,System.Object} | - | Additional HTML attributes to apply to the input element. |
| BorderColor | Spectre.Console.Color | - | Border color when input is not focused and not disabled. |
| BorderPadding | Spectre.Console.Padding | - | Padding between the border and the content. |
| BorderStyle | Spectre.Console.BoxBorder | - | Style of the input border. |
| ContentPadding | Spectre.Console.Padding | - | Padding around the input content. |
| Disabled | System.Boolean | - | Whether the input is disabled. When disabled, cannot receive focus or accept input. |
| DisabledBorderColor | Spectre.Console.Color | - | Border color when input is disabled. |
| Expand | System.Boolean | - | Whether the input should expand to fill available horizontal space. |
| FocusOrder | System.Nullable{System.Int32} | - | Tab order for keyboard navigation. Lower values receive focus first. If `null`, natural document order is used. |
| FocusedBorderColor | Spectre.Console.Color | - | Border color when input has focus. |
| Label | System.String | - | Label text displayed above the input field. If null or empty, no label is shown. |
| LabelColor | Spectre.Console.Color | - | Color of the label text. |
| LabelDecoration | Spectre.Console.Decoration | - | Decoration style of the label text. |
| MaskInput | System.Boolean | - | Whether input characters should be masked (displayed as bullets). Useful for password fields. Default is `false`. |
| OnBlur | Microsoft.AspNetCore.Components.EventCallback{Microsoft.AspNetCore.Components.Web.FocusEventArgs} | - | Event callback invoked when input loses focus. |
| OnFocus | Microsoft.AspNetCore.Components.EventCallback{Microsoft.AspNetCore.Components.Web.FocusEventArgs} | - | Event callback invoked when input receives focus. |
| OnInput | Microsoft.AspNetCore.Components.EventCallback{System.String} | - | Event callback invoked on each character input (fired for every keystroke). |
| OnSubmit | Microsoft.AspNetCore.Components.EventCallback{System.String} | - | Event callback invoked when submitting input (typically by pressing Enter). |
| Placeholder | string? | - | Placeholder text shown when input is empty. |
| PlaceholderColor | Spectre.Console.Color | - | Color of the placeholder text. |
| PlaceholderDecoration | Spectre.Console.Decoration | - | Decoration style of the placeholder text. |
| Value | string | - | Current value of the text input. Supports two-way binding with @bind-Value. |
| ValueChanged | EventCallback | - | Event callback invoked when the value changes. |
| ValueColor | Spectre.Console.Color | - | Color of the input value text. |
| ValueExpression | System.Linq.Expressions.Expression{System.Func{System.String}} | - | Expression identifying the bound value for validation scenarios with EditContext. |
### Usage Example (TextInput_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
@code {
private static readonly Padding _inputPadding = new(1, 0, 1, 0);
private string _firstName = string.Empty;
private string _secretNote = string.Empty;
private string PreviewText => _firstName.Length == 0
? "Preview: (none)"
: $"Preview: {_firstName}";
private string SecretLengthText => $"Stored secret length: {_secretNote.Length}";
private Task OnFirstNameChangedAsync(string? value)
{
_firstName = value ?? string.Empty;
StateHasChanged();
return Task.CompletedTask;
}
private Task OnSecretChangedAsync(string? value)
{
_secretNote = value ?? string.Empty;
StateHasChanged();
return Task.CompletedTask;
}
}
````
---
# Component: TextButton
Interactive button component.
### Parameters:
| Name | Type | Default | Description |
| --------------- | --------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------- |
| BackgroundColor | Spectre.Console.Color | - | Background color when not focused. Default is Default. |
| Content | System.String | - | Text content displayed on the button. |
| FocusOrder | System.Nullable{System.Int32} | - | Tab order for keyboard navigation. Lower values receive focus first. If `null`, natural document order is used. |
| FocusedColor | Spectre.Console.Color | - | Background color when focused. Default is DeepSkyBlue1. |
| OnClick | Microsoft.AspNetCore.Components.EventCallback | - | Event callback invoked when the button is clicked. |
### Usage Example (TextButton_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
Count: @count
@code {
private int count = 0;
private void HandleClick()
{
count++;
StateHasChanged();
}
}
````
---
# Component: FlexBox
Lays out children using a CSS-like flexbox model with configurable direction, justification, alignment, wrapping, and gap.
### Parameters:
| Name | Type | Default | Description |
| ------------ | ---------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Align | FlexAlign | - | How items are aligned along the cross axis. Default is Start. |
| ChildContent | Microsoft.AspNetCore.Components.RenderFragment | - | The child content to lay out within the flex container. |
| Direction | FlexDirection | - | Lays out child content using a CSS-like flexbox model with configurable direction,
justification, alignment, wrapping, and gap. |
| Gap | int | - | Spacing between items along the main axis in characters (Row) or lines (Column). Default is 0. |
| Height | int? | - | Explicit height constraint in lines. When null, uses the natural content height. |
| Justify | FlexJustify | - | How free space is distributed along the main axis. Default is Start. |
| Width | int? | - | Explicit width constraint in characters. When null, uses all available width. |
| Wrap | FlexWrap | - | Whether items wrap to new lines when they exceed the available space. Default is NoWrap. |
### Usage Example (FlexBox_1.razor):
````razor
@using Spectre.Console
@using RazorConsole.Components
@using RazorConsole.Core.Renderables
@* ── Name fields with SpaceBetween ── *@
@* ── Email field full width ── *@
@* ── Password field full width ── *@
@* ── Role selector with description ── *@
@* ── Interests (wrapping tags) ── *@
@foreach (var interest in _interests)
{
}
@* ── Action buttons ── *@
@* ── Status line ── *@
@code {
private static readonly Padding _inputPadding = new(1, 0, 1, 0);
private static readonly string[] _roles = ["Viewer", "Editor", "Admin"];
private static readonly string[] _interests =
["C#", "RazorConsole", "Razor", "Blazor", "Spectre.Console", "TUI", "CLI", "DevOps", "AI"];
private string _firstName = string.Empty;
private string _middleName = string.Empty;
private string _lastName = string.Empty;
private string _email = string.Empty;
private string _password = string.Empty;
private string? _selectedRole;
private string? _focusedRole;
private readonly HashSet _selectedInterests = new();
private string _statusText = "Fill out the form and press Submit.";
private Color _statusColor = Color.Grey70;
private bool IsSelected(string interest) => _selectedInterests.Contains(interest);
private void ToggleInterest(string interest)
{
if (!_selectedInterests.Remove(interest))
{
_selectedInterests.Add(interest);
}
StateHasChanged();
}
private Task OnFirstNameChanged(string? v)
{
_firstName = v ?? string.Empty;
StateHasChanged();
return Task.CompletedTask;
}
private Task OnMiddleNameChanged(string? v)
{
_middleName = v ?? string.Empty;
StateHasChanged();
return Task.CompletedTask;
}
private Task OnLastNameChanged(string? v)
{
_lastName = v ?? string.Empty;
StateHasChanged();
return Task.CompletedTask;
}
private Task OnEmailChanged(string? v)
{
_email = v ?? string.Empty;
StateHasChanged();
return Task.CompletedTask;
}
private Task OnPasswordChanged(string? v)
{
_password = v ?? string.Empty;
StateHasChanged();
return Task.CompletedTask;
}
private void HandleCancel()
{
_firstName = string.Empty;
_middleName = string.Empty;
_lastName = string.Empty;
_email = string.Empty;
_password = string.Empty;
_selectedRole = null;
_selectedInterests.Clear();
_statusText = "Form cleared.";
_statusColor = Color.Yellow;
StateHasChanged();
}
private void HandleSubmit()
{
if (string.IsNullOrWhiteSpace(_firstName) || string.IsNullOrWhiteSpace(_email))
{
_statusText = "⚠ First name and email are required.";
_statusColor = Color.Red;
}
else
{
var interests = _selectedInterests.Count > 0
? string.Join(", ", _selectedInterests)
: "none";
var fullName = string.IsNullOrWhiteSpace(_middleName)
? $"{_firstName} {_lastName}"
: $"{_firstName} {_middleName} {_lastName}";
_statusText = $"✔ Registered {fullName} as {_selectedRole ?? "Viewer"} with interests: {interests}.";
_statusColor = Color.Green;
}
StateHasChanged();
}
}
````