artisanal_widgets
Flutter-inspired widget framework for terminal UIs, built on top of
artisanal.
This is the package for widget-first apps. Widget APIs, runners, and test
helpers are owned here; the core artisanal package does not re-export them.
Table of Contents
- Installation
- Import
- Quick start
- Flutter-style component ports
- Program Instrumentation
- Tests
- Command execution note
Installation
dependencies:
artisanal_widgets: ^0.4.0
Import
import 'package:artisanal_widgets/app.dart';
import 'package:artisanal_widgets/widgets.dart';
Use the focused stable entrypoints when you need those modules:
package:artisanal_widgets/app.dartfor app shells, runners, reload helpers, and hosted wrapperspackage:artisanal_widgets/charting.dartfor chart widgetspackage:artisanal_widgets/editors.dartforTextField,TextArea,TextEditor,CodeEditor,MarkdownEditor, and the stableTextInputKeyMap/TextAreaKeyMapcustomization surfacepackage:artisanal_widgets/selection.dartforSelectableTextandSelectionAreapackage:artisanal_widgets/testing.dartforWidgetTester
The main package:artisanal_widgets/widgets.dart barrel also re-exports
KeyMap and KeyBinding, so component-level shortcut UIs such as HelpView
and zone-hit messages such as ZoneInBoundsMsg, so shortcut and pointer-aware
widgets do not need an extra package:artisanal/tui.dart import.
Keep package:artisanal_widgets/artisanal_widgets.dart only when you
explicitly want the broader experimental compatibility surface.
Both the local runner helpers and the hosted browser/socket helpers accept an
imageAutoMode override. Hosted browser/socket runners now default
Image(renderMode: auto) to session-driven capability detection, while
WidgetTester keeps the portable half-block fallback for deterministic tests.
Quick start
import 'package:artisanal_widgets/app.dart';
import 'package:artisanal_widgets/widgets.dart';
class HelloApp extends StatelessWidget {
HelloApp({super.key});
@override
Widget build(BuildContext context) {
final theme = ThemeScope.of(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Hello widgets', style: theme.titleLarge),
Text('Press q to quit', style: theme.bodyMedium),
],
);
}
}
void main() async {
await runWidgetApp(
ArtisanalApp(
title: 'Hello widgets',
home: HelloApp(),
),
);
}
runWidgetApp() defaults to MouseMode.allMotion, so hover-driven widgets
such as Tooltip, MouseRegion, and hover-aware scrollbars work without extra
setup. If you call runtime.runProgram() directly, set
mouseMode: runtime.MouseMode.allMotion for passive hover behavior. Setting
only mouse: true enables MouseMode.cellMotion instead.
Flutter-style component ports
- Chips:
Chip,ActionChip,ChoiceChip,FilterChip,InputChip - Menus:
DropdownButton,DropdownMenuItem,PopupMenuButton,PopupMenuItem,CheckedPopupMenuItem,PopupMenuDivider - Sliders:
Slider,RangeSlider,RangeValues - Indicators:
LinearProgressIndicator,CircularProgressIndicator - Data display:
DataTable.cellswith column spans and alignment,MonthlyCalendar, and terminal-cellShadowpresets - Charts:
SparklineChart,LineChart,BarChart,HeatmapChart,PieChart,RibbonChartwith optional in-chart legends
The example/widget_features app combines these components with a fixed
terminal viewport, UV subtree filters, and world-coordinate canvas shapes.
For a focused effects walkthrough, run
dart run example/uv_effects/main.dart; it compares an ordinary widget tree
with a CellFilter-processed copy and includes a composed filter stack.
For a production-style primary-screen example, run
dart run example/inline_build_monitor/main.dart. It keeps a responsive build
dashboard pinned at the bottom while staged command output streams into native
terminal scrollback. Press p to pause, r to rebuild, e to simulate a
failure, or q to quit.
The OpenCode example is self-contained under
example/opencode (including local data models and theme assets).

Program Instrumentation
The core TUI runtime (Program) supports general instrumentation and automation
for any app (not OpenCode-specific):
ProgramInterceptorfor message interception/timing hooks.ProgramReplayfor deterministic event playback.
import 'package:artisanal/tui.dart' as runtime;
import 'package:artisanal_widgets/app.dart';
final replay = runtime.ProgramReplay.script([
runtime.ProgramReplayStep(
after: Duration(milliseconds: 120),
msg: runtime.KeyMsg(
runtime.Key(runtime.KeyType.runes, runes: [0x61]),
),
),
runtime.ProgramReplayStep(
after: Duration(milliseconds: 16),
msg: runtime.QuitMsg(),
),
]);
await runtime.runProgram(
WidgetApp(MyApp()),
options: runtime.ProgramOptions(replay: replay),
);
See the package:artisanal/tui.dart API docs for full interceptor/replay
details.
Tests
Component tests are split by widget under
test/components/*_test.dart.
Useful commands:
dart test test/components
dart test
dart analyze
Command execution note
When combining commands that include runtime-managed commands (EveryCmd,
StreamCmd, or helpers like every(...)), use ParallelCmd so those commands
are started by Program.
Use Cmd.batch(...) for finite commands that only need execute().
Demo captures
Recordings of some of the more consequential examples, regenerated from the
VHS tapes in example/.vhs/ with
task widgets-demos. Every recorded example also has a page with a preview
and its full source on the documentation site.
Widget app shell (example/artisanal_app/main.dart):

Charting (example/charting/main.dart):

Git diff viewer (example/git-diff/main.dart):

Data table (example/data_table/main.dart):

Command palette (example/command_palette/main.dart):

Code editor (example/code-editor/main.dart):

Markdown editor (example/markdown-editor/main.dart):

Data visualization (example/dataviz/main.dart):

Debug console (example/debug_console/main.dart):

OpenCode chat UI (example/opencode/main.dart):

Buttons & badges (example/buttons/main.dart):

Form inputs (example/inputs/main.dart):

Text field (example/text-field/main.dart):

Text area (example/text-area/main.dart):

Tree view (example/tree_view/main.dart):

Tabs & breadcrumbs (example/tabs_nav/main.dart):

Text selection (example/selection/main.dart):

Progress & spinner (example/progress_spinner/main.dart):

Slider (example/slider/main.dart):

Scrolling (example/scroll/main.dart):

File picker (example/file_picker/main.dart):

Help view (example/help_view/main.dart):

Libraries
- charting Charts
- Stable chart widget entrypoint for terminal UIs.
- editors Editors
- Stable editor and text-input entrypoint for terminal widget apps.
- selection Selection
- Stable text selection widget entrypoint for terminal UIs.
- testing Testing
- Testing utilities for TUI widgets.
- app TUI
- Stable app-shell entrypoint for terminal widget apps.
- artisanal_widgets TUI
- Legacy broad widget entrypoint for composable TUI components.
- widgets TUI
- Stable high-level widget framework for building terminal UIs.