ThemePanelWidget
Apply scoped theme mutations to a subtree of widgets.
ThemePanelWidget allows you to override specific theme values for a child widget and all its descendants. The theme mutations only affect the subtree—once rendering exits the ThemePanel, the original theme is restored.
Basic Usage
Create a ThemePanel with a theme mutator function using the fluent API:
using Hex1b;
using Hex1b.Theming;
await using var terminal = Hex1bTerminal.CreateBuilder()
.WithHex1bApp((app, options) => ctx =>
{
// Danger zone theme mutator
Func<Hex1bTheme, Hex1bTheme> dangerTheme = theme => theme.Clone()
.Set(GlobalTheme.ForegroundColor, Hex1bColor.FromRgb(255, 100, 100))
.Set(BorderTheme.BorderColor, Hex1bColor.FromRgb(180, 0, 0))
.Set(BorderTheme.TitleColor, Hex1bColor.Red)
.Set(ButtonTheme.BackgroundColor, Hex1bColor.FromRgb(100, 0, 0))
.Set(ButtonTheme.ForegroundColor, Hex1bColor.White)
.Set(ButtonTheme.FocusedBackgroundColor, Hex1bColor.Red)
.Set(ToggleSwitchTheme.FocusedSelectedBackgroundColor, Hex1bColor.Red)
.Set(ToggleSwitchTheme.UnfocusedSelectedBackgroundColor, Hex1bColor.FromRgb(100, 0, 0));
return ctx.VStack(v => [
v.Border(b => [
b.Text(" General Settings"),
b.HStack(h => [
h.Text("Telemetry: "),
h.ToggleSwitch(["Off", "On"], 1)
])
], title: "⚙ Settings"),
v.Text(""),
v.ThemePanel(dangerTheme, danger => [
danger.Border(db => [
db.Text(" These actions cannot be undone!"),
db.HStack(h => [
h.Text("Factory reset: "),
h.ToggleSwitch(["No", "Yes"], 0)
]),
db.Button("☠ Wipe Everything")
], title: "⚠ DANGER ZONE")
])
]);
})
.Build();
await terminal.RunAsync();dotnet runFunctional API
ThemePanelWidget uses a Func<Hex1bTheme, Hex1bTheme> pattern. Your function receives the current theme and returns a modified copy. Use .Clone() to create a new theme instance before applying modifications.
How Theme Mutations Work
ThemePanelWidget uses a functional approach to theme modification:
- Receives current theme: The mutator function receives the active theme at render time
- Returns modified theme: You return a new theme with your modifications applied
- Scoped application: The modified theme applies only to the child subtree
- Automatic restoration: After rendering the child, the original theme is restored
// The mutator function signature
Func<Hex1bTheme, Hex1bTheme> mutator = theme => theme.Clone()
.Set(GlobalTheme.ForegroundColor, Hex1bColor.Green);2
3
Theming Buttons
ThemePanels work with interactive widgets like buttons:
You can customize any theme element within the ThemePanel scope:
Nesting ThemePanels
ThemePanels can be nested to create layered theme overrides:
Each nested ThemePanel starts with the theme from its parent context and applies additional mutations:
VStack Builder Overload
For convenience, ThemePanel provides a VStack builder overload:
// These are equivalent:
ctx.ThemePanel(theme => theme.Set(...), ctx.VStack(v => [...]))
ctx.ThemePanel(theme => theme.Set(...), v => [
v.Text("Line 1"),
v.Text("Line 2")
])2
3
4
5
6
7
Layout Behavior
ThemePanelWidget has no visual presence—it only affects theming:
- Measuring: The child is measured with the full constraints
- Arranging: The child gets the full bounds of the ThemePanel
- Rendering: Theme is swapped, child is rendered, theme is restored
- No size overhead: ThemePanel adds zero pixels to the layout
Focus Behavior
ThemePanelWidget is not focusable:
- Focus passes through to focusable children
- The ThemePanel itself cannot receive focus
- Tab navigation works normally within themed content
Common Patterns
Danger Zones
Create visually distinct danger areas:
Information Sections
Highlight informational content:
Success Feedback
Style success states:
Combined with Border
ThemePanel pairs well with BorderWidget for styled containers:
Related Widgets
- BorderWidget - For decorative borders
- Theming Guide - Comprehensive theming documentation