Tabbed Fragments
Demonstrates every documented Router API in a multi-level fragment hierarchy with tabbed navigation, outward communication, and theme cycling.
Architecture
App (root) βββ TabBar β bubble TabSelected on [/] or click βββ CounterTab β 7 counters across 4 levels β βββ Left Panel β β βββ LT Leaf β β βββ LB Leaf β βββ Right Panel β βββ RT Leaf β βββ RB Leaf βββ ColorTab β scrollable color picker βββ Controls β stateless hotkey display
Hotkeys
| Key | Action |
|---|---|
[ / ] |
Switch tabs |
| Click | Select tab in TabBar |
t |
Cycle theme (cyan β green β magenta β yellow) |
q |
Quit |
Ctrl+C |
Force quit |
Counter Tab:
| Key | Action |
|---|---|
1β4 |
Increment leaves (LT, LB, RT, RB) |
a / b |
Increment panels (Left, Right) |
Enter |
Increment root counter |
Color Tab:
| Key | Action |
|---|---|
1β6 |
Select color |
Enter |
Random color |
Router API Coverage
Every Router API is exercised somewhere in the hierarchy:
| API | Fragment | Purpose |
|---|---|---|
route |
App, CounterTab, Panel | Declare child fragment routes |
action |
App | Named :quit handler |
forward_events with as: |
App | Semantic envelope routing (keys β Message::Routed) |
forward_routed with as: |
CounterTab, Panel | Envelope transformation between layers |
forward_instances_of with broadcast: |
App | Resize to all routes |
receive_events |
TabBar | [/] navigation |
receive_routed |
CounterTab, Panel, Leaf | Handle semantic envelopes |
intercept_events |
App | q, Ctrl+C |
intercept_all with unless: |
CounterTab, ColorTab | Disable input when inactive |
intercept_instances_of |
Panel | Transform LeafReset β PanelChildReset |
observe_all |
App | Count all messages |
observe_instances_of |
App, CounterTab | Track resets, milestones, tab/color/theme changes |
only/skip guards |
App | Conditional routing by active tab |
route_to blocks |
App, CounterTab | Scoped destination for multiple forwards |
otherwise |
App | Fallback routing to TabBar |
from_router |
All | Generate Update from declarations |
Command.bubble |
Leaf, Panel, ColorTab, TabBar | Outward communication through hierarchy |
Command.deliver |
Leaf, Panel | Fire-and-forget milestones to Root |
Message::Predicates |
All messages | Type predicates (e.g., message.milestone?) |
Key Concepts
-
Semantic envelope transformation. Each layer speaks its childβs API, not raw key names. App sends
:counter_1; CounterTab transforms to:leaf_1; Panel transforms to:increment. Change keybindings at Root without touching inner fragments. -
Outward communication. Leaves
bubbleresets through the hierarchy. Panels intercept, add context, and re-bubble asPanelChildReset. Leaves alsodelivermilestones directly to Root, bypassing intermediate fragments. -
Guard-based routing.
only when: COUNTER_ACTIVEscopes an entire block offorward_eventsdeclarations to the active tab. Inactive tabs useintercept_allwithunless:to silently swallow input. -
Observe without blocking.
observe_allcounts every message without preventing other handlers from running.observe_instances_oftracks resets and milestones as side effects. -
Mouse support. TabBar handles
mouse_left_downevents for click-to- select tabs, demonstrating mouse event routing alongside keyboard input.
Usage
ruby examples/app_tabbed_fragments/app.rb
See Also
-
Fractal Dashboard β Simpler Router example with async commands and a modal overlay
-
Router-Based Composition Patterns β Full guide to the Router DSL