Wijjit

Getting Started

  • Installation
    • Requirements
    • Install Wijjit
      • From PyPI (recommended)
      • From source (development)
    • Verify your environment
    • Dependencies
    • Platform notes
      • Windows
      • Linux
      • macOS
    • Troubleshooting
    • Next steps
  • Quick Start
    • Hello World
      • Understanding the Code
    • Adding a Frame
    • Adding State and Input
      • Key Concepts Demonstrated
    • Login Form Example
      • Features Shown
    • Common Patterns
      • Keyboard Shortcuts
      • Navigation Between Views
      • Working with Lists
    • Next Steps
    • Where to Go From Here
  • Tutorial: Persistent Todo App
    • What you’ll build
    • Prerequisites
    • Project layout
    • Step 1 – bootstrap the app and storage helpers
    • Step 2 – render the UI with template tags
    • Step 3 – wire actions and keyboard shortcuts
    • Step 4 – polish and run
    • Full source listing
    • Next steps
  • Tutorial: Chatbot
    • What you’ll build
    • Prerequisites
    • Step 1 - state and a bot
    • Step 2 - render the chat window with LogView
    • Step 3 - stream the reply
    • Step 4 - run it
    • Where to next
  • Tutorial: Terminal Spreadsheet
    • What you’ll build
    • Prerequisites
    • Step 1 - optional dependency and file I/O
    • Step 2 - chart data and app state
    • Step 3 - the layout
    • Step 4 - reading the grid’s live edits
    • Step 5 - run it
    • Where to next

User Guide

  • Core Concepts
    • Application lifecycle
    • Views and routing
    • State & reactivity
    • Rendering pipeline
    • Event flow
    • Working asynchronously
    • Putting it together
  • State Management
    • State fundamentals
    • In-place mutation and the order that matters
    • Common mutation patterns
      • Single key updates
      • Batch updates
      • Multi-key and whole-state updates
      • Watching specific keys
    • Keys that share a name with a State method
    • Async and background work
    • Derived & computed data
    • Validation & error reporting
    • Refreshing manually
    • Testing tips
  • Templates & Tags
    • Layout primitives
    • Attributes every element accepts
    • Form & input tags
      • The bind attribute
    • Display & data tags
    • Notifications & dialogs
    • Templates in files (the templates/ directory)
    • Binding data into templates
    • Best practices
  • Event Handling
    • Event types
    • Registering handlers
    • Handler scopes & lifetimes
    • Actions & change events
    • Keyboard shortcuts
    • Mouse handling
    • Element event callbacks
    • Asynchronous handlers
    • Error handling & debugging
    • Best practices
  • Layout System
    • Mental model
    • Sizing options
    • Margins, padding, spacing
    • Stacks
    • Grid
    • Frames
    • Scroll management
      • Horizontal scrolling
    • Alignment & distribution
    • Responsive techniques
    • Debugging layouts
    • Checklist
  • Components
    • Form inputs
    • Display widgets
    • Data Visualization
    • Menus & overlays
    • Container widgets
    • Custom components
      • Shipping an element as its own package
    • Tips
  • Modal Dialogs & Overlays
    • Overlay layers
    • Showing a modal from a template
    • Creating overlays programmatically
    • Templated dialogs
    • Dropdowns & context menus
    • Closing overlays
    • Stacking & multiple overlays
    • Notifications & toasts
    • Tips
  • Inline Rendering
    • One-shot Rendering
      • Options
    • Interactive Inline Apps
      • InlineApp Parameters
    • Keyboard Input
      • Methods
    • Animation Support
    • Comparison with Full-Screen Apps
    • Examples
  • Focus Navigation
    • How focus is determined
    • Initial focus: the autofocus attribute
    • Built-in navigation
    • When Tab belongs to the element instead
    • Focus cycling in modals
    • Making elements focusable
    • Working inside scrollable containers
    • Managing focus manually
    • Troubleshooting tips
  • Mouse Support
    • Event pipeline
    • Supported gestures
    • Writing mouse-aware elements
    • Hover effects & tooltips
    • Menus & context clicks
    • Platform notes
    • Debugging
  • Styling & Themes
    • Building blocks
    • Theme lookup flow
    • Changing the theme
    • Overrides in templates
    • Dynamic styling
    • Built-in style classes
    • Global focus color
    • Scrollbar theming
    • Modal vs Frame styles
    • Placeholder text styling
    • Advanced theming tips
    • Testing & verification
    • Where to go next
  • Configuration
    • Overview
    • Quick Start
    • Configuration Loading Methods
      • 1. Direct Assignment
      • 2. Bulk Update
      • 3. From Python File
      • 4. From Python Object
      • 5. From Environment Variable
      • 6. From Prefixed Environment Variables
    • Configuration Options Reference
      • Input & Interaction (4 options)
        • ENABLE_MOUSE
        • MOUSE_TRACKING_MODE
        • ENABLE_FOCUS_NAVIGATION
        • QUIT_KEY
      • Display & Terminal (5 options)
        • USE_ALTERNATE_SCREEN
        • HIDE_CURSOR
        • APP_TITLE
        • HARDWARE_CURSOR
        • REMOTE
      • Process Control (1 option)
        • ENABLE_SUSPEND
      • Colors & Theming (6 options)
        • FOCUS_COLOR
        • NO_COLOR
        • DEFAULT_THEME
        • THEME_FILE
        • STYLE_FILE
        • UNICODE_SUPPORT
      • Performance & Threading (4 options)
        • REFRESH_INTERVAL
        • MAX_FPS
        • RUN_SYNC_IN_EXECUTOR
        • EXECUTOR_MAX_WORKERS
      • Rendering (3 options)
        • RENDER_THROTTLE_MS
        • FULL_REPAINT_INTERVAL
        • AUTO_FIT_LAYOUT
      • Notifications (5 options)
        • NOTIFICATION_DURATION
        • NOTIFICATION_POSITION
        • NOTIFICATION_SPACING
        • NOTIFICATION_MARGIN
        • NOTIFICATION_MAX_STACK
      • Logging (4 options)
        • LOG_LEVEL
        • LOG_FILE
        • LOG_FORMAT
        • SUPPRESS_INTERNAL_LOGGING_CONFIG
      • Debug & Development (6 options)
        • DEBUG
        • SHOW_FPS
        • SHOW_BOUNDS
        • DEBUG_INPUT_KEYBOARD
        • DEBUG_INPUT_MOUSE
        • WARN_SLOW_RENDER_MS
      • Templates (2 options)
        • TEMPLATE_DIR
        • TEMPLATE_AUTO_RELOAD
      • Accessibility (2 options)
        • REDUCE_MOTION
        • HIGH_CONTRAST
    • Common Use Cases
      • Development Environment
      • Production Environment
      • Keyboard-Only Mode
      • Custom Theme with Styles
      • Performance Monitoring
      • CI/CD Testing
    • Best Practices
      • 1. Use Configuration Files for Environments
      • 2. Environment Variables for Secrets
      • 3. Validate Configuration
      • 4. Use Config Namespaces
      • 5. Document Custom Configurations
    • Troubleshooting
      • Configuration Not Applied
      • Environment Variables Not Loaded
      • Theme File Not Loading
      • Invalid Config Values
    • Examples
    • API Reference
      • Config Class
      • DefaultConfig Class
    • See Also
  • Testing Your App
    • The harness
    • Driving input
    • Waiting for asynchronous updates
    • Inspecting the result
    • Assertions
    • Pytest fixtures
    • Building an app from a template
    • Driving apps from the command line
  • Performance
    • The headline number
    • What the diff renderer buys you
    • Measured results
      • Terminal I/O per frame
      • Render latency
    • Startup cost
    • What is slow, and what to avoid
    • Profiling your own app

API Reference

  • Core API
    • Application lifecycle
      • wijjit.core.app.Wijjit
        • Wijjit
    • Inline rendering
      • wijjit.render_inline()
      • wijjit.InlineApp
    • Event loop & routing
      • wijjit.core.event_loop.EventLoop
        • EventLoop
      • wijjit.core.view_router.ViewRouter
        • ViewRouter
      • wijjit.core.view_router.ViewConfig
        • ViewConfig
      • wijjit.core.renderer.Renderer
        • Renderer
      • wijjit.core.render_context.RenderContext
        • RenderContext
    • View templating
      • wijjit.core.templating.RenderedView
        • RenderedView
      • wijjit.render_template_string()
      • wijjit.render_template()
    • Virtual DOM & Reconciliation
      • wijjit.core.vdom.VNode
        • VNode
      • wijjit.core.vdom.VNodeBuilder
        • VNodeBuilder
      • wijjit.core.reconciler.Reconciler
        • Reconciler
      • wijjit.core.reconciler.DiffType
        • DiffType
      • wijjit.core.element_registry.ElementRegistry
        • ElementRegistry
    • Interaction managers
      • wijjit.core.focus.FocusManager
        • FocusManager
      • wijjit.core.hover.HoverManager
        • HoverManager
      • wijjit.core.mouse_router.MouseEventRouter
        • MouseEventRouter
      • wijjit.core.overlay.OverlayManager
        • OverlayManager
      • wijjit.core.notification_manager.NotificationManager
        • NotificationManager
      • wijjit.core.wiring.ElementWiringManager
        • ElementWiringManager
    • Supporting structures
      • wijjit.core.overlay.LayerType
        • LayerType
      • wijjit.core.overlay.Overlay
        • Overlay
  • Configuration API
    • wijjit.config.Config
      • Config
        • Config.__init__()
        • Config.from_object()
        • Config.from_pyfile()
        • Config.from_envvar()
        • Config.from_mapping()
        • Config.from_prefixed_env()
        • Config.get_namespace()
    • wijjit.config.DefaultConfig
      • DefaultConfig
        • DefaultConfig.__init__()
        • DefaultConfig.ENABLE_MOUSE
        • DefaultConfig.MOUSE_TRACKING_MODE
        • DefaultConfig.ENABLE_FOCUS_NAVIGATION
        • DefaultConfig.QUIT_KEY
        • DefaultConfig.USE_ALTERNATE_SCREEN
        • DefaultConfig.HIDE_CURSOR
        • DefaultConfig.HARDWARE_CURSOR
        • DefaultConfig.APP_TITLE
        • DefaultConfig.NO_COLOR
        • DefaultConfig.FOCUS_COLOR
        • DefaultConfig.DEFAULT_THEME
        • DefaultConfig.THEME_FILE
        • DefaultConfig.STYLE_FILE
        • DefaultConfig.UNICODE_SUPPORT
        • DefaultConfig.AUTO_FIT_LAYOUT
        • DefaultConfig.REFRESH_INTERVAL
        • DefaultConfig.MAX_FPS
        • DefaultConfig.RUN_SYNC_IN_EXECUTOR
        • DefaultConfig.EXECUTOR_MAX_WORKERS
        • DefaultConfig.RENDER_THROTTLE_MS
        • DefaultConfig.FULL_REPAINT_INTERVAL
        • DefaultConfig.NOTIFICATION_DURATION
        • DefaultConfig.NOTIFICATION_POSITION
        • DefaultConfig.NOTIFICATION_SPACING
        • DefaultConfig.NOTIFICATION_MARGIN
        • DefaultConfig.NOTIFICATION_MAX_STACK
        • DefaultConfig.LOG_LEVEL
        • DefaultConfig.LOG_FILE
        • DefaultConfig.LOG_FORMAT
        • DefaultConfig.SUPPRESS_INTERNAL_LOGGING_CONFIG
        • DefaultConfig.DEBUG
        • DefaultConfig.SHOW_FPS
        • DefaultConfig.SHOW_BOUNDS
        • DefaultConfig.DEBUG_INPUT_KEYBOARD
        • DefaultConfig.DEBUG_INPUT_MOUSE
        • DefaultConfig.WARN_SLOW_RENDER_MS
        • DefaultConfig.TEMPLATE_DIR
        • DefaultConfig.TEMPLATE_AUTO_RELOAD
        • DefaultConfig.ENABLE_SUSPEND
        • DefaultConfig.REMOTE
        • DefaultConfig.REDUCE_MOTION
        • DefaultConfig.HIGH_CONTRAST
  • State API
    • Key classes
      • wijjit.core.state.State
        • State
    • Usage highlights
  • Events API
    • Event types
      • wijjit.core.events.Event
        • Event
      • wijjit.core.events.KeyEvent
        • KeyEvent
      • wijjit.core.events.ActionEvent
        • ActionEvent
      • wijjit.core.events.ChangeEvent
        • ChangeEvent
      • wijjit.core.events.FocusEvent
        • FocusEvent
      • wijjit.core.events.MouseEvent
        • MouseEvent
      • wijjit.core.events.EventType
        • EventType
      • wijjit.core.events.HandlerScope
        • HandlerScope
    • Handlers & registry
      • wijjit.core.events.Handler
        • Handler
      • wijjit.core.events.HandlerRegistry
        • HandlerRegistry
  • Layout API
    • Size & geometry
      • wijjit.layout.bounds.Bounds
        • Bounds
      • wijjit.layout.bounds.Size
        • Size
      • wijjit.layout.bounds.parse_size
        • parse_size()
      • wijjit.layout.bounds.parse_margin
        • parse_margin()
    • Engine primitives
      • wijjit.layout.engine.LayoutNode
        • LayoutNode
      • wijjit.layout.engine.ElementNode
        • ElementNode
      • wijjit.layout.engine.Container
        • Container
      • wijjit.layout.engine.VStack
        • VStack
      • wijjit.layout.engine.HStack
        • HStack
      • wijjit.layout.engine.SizeConstraints
        • SizeConstraints
    • Frames & scrolling
      • wijjit.layout.frames.Frame
        • Frame
      • wijjit.layout.frames.FrameStyle
        • FrameStyle
      • wijjit.layout.frames.BorderStyle
        • BorderStyle
      • wijjit.layout.scroll.ScrollManager
        • ScrollManager
      • wijjit.layout.scroll.render_vertical_scrollbar
        • render_vertical_scrollbar()
    • Dirty tracking
      • wijjit.layout.dirty.DirtyRegionManager
        • DirtyRegionManager
  • Elements API
    • Base classes
      • wijjit.elements.base.Element
        • Element
      • wijjit.elements.base.ElementType
        • ElementType
      • wijjit.elements.base.ScrollableElement
        • ScrollableElement
      • wijjit.elements.base.OverlayElement
        • OverlayElement
      • wijjit.elements.base.TextElement
        • TextElement
    • Input widgets
      • wijjit.elements.input.button.Button
        • Button
      • wijjit.elements.input.checkbox.Checkbox
        • Checkbox
      • wijjit.elements.input.checkbox.CheckboxGroup
        • CheckboxGroup
      • wijjit.elements.input.radio.Radio
        • Radio
      • wijjit.elements.input.radio.RadioGroup
        • RadioGroup
      • wijjit.elements.input.select.Select
        • Select
      • wijjit.elements.input.slider.Slider
        • Slider
      • wijjit.elements.input.toggle.Toggle
        • Toggle
      • wijjit.elements.input.text.TextInput
        • TextInput
      • wijjit.elements.input.text.TextArea
        • TextArea
      • wijjit.elements.input.text.InputStyle
        • InputStyle
      • wijjit.elements.input.code_editor.CodeEditor
        • CodeEditor
      • wijjit.elements.input.code_editor.SyntaxHighlighter
        • SyntaxHighlighter
      • wijjit.elements.input.datagrid.DataGrid
        • DataGrid
    • Display widgets
      • wijjit.elements.display.table.Table
        • Table
      • wijjit.elements.display.list.ListView
        • ListView
      • wijjit.elements.display.tree.Tree
        • Tree
      • wijjit.elements.display.logview.LogView
        • LogView
      • wijjit.elements.display.progress.ProgressBar
        • ProgressBar
      • wijjit.elements.display.spinner.Spinner
        • Spinner
      • wijjit.elements.display.statusbar.StatusBar
        • StatusBar
      • wijjit.elements.display.status_indicator.StatusIndicator
        • StatusIndicator
      • wijjit.elements.display.contentview.ContentView
        • ContentView
      • wijjit.elements.display.notification.NotificationElement
        • NotificationElement
      • wijjit.elements.display.link.Link
        • Link
      • wijjit.elements.display.tabbed_panel.TabbedPanel
        • TabbedPanel
      • wijjit.elements.display.pager.Pager
        • Pager
      • wijjit.elements.display.pager.Page
        • Page
      • wijjit.elements.display.image.ImageView
        • ImageView
    • Data Visualization
      • wijjit.elements.display.sparkline.Sparkline
        • Sparkline
      • wijjit.elements.display.barchart.BarChart
        • BarChart
      • wijjit.elements.display.columnchart.ColumnChart
        • ColumnChart
      • wijjit.elements.display.linechart.LineChart
        • LineChart
      • wijjit.elements.display.gauge.Gauge
        • Gauge
      • wijjit.elements.display.heatmap.HeatMap
        • HeatMap
      • wijjit.elements.display.chart_utils.BrailleCanvas
        • BrailleCanvas
    • Menus & modals
      • wijjit.elements.menu.DropdownMenu
        • DropdownMenu
      • wijjit.elements.menu.ContextMenu
        • ContextMenu
      • wijjit.elements.menu.MenuElement
        • MenuElement
      • wijjit.elements.modal.ModalElement
        • ModalElement
      • wijjit.elements.modal.AlertDialog
        • AlertDialog
      • wijjit.elements.modal.ConfirmDialog
        • ConfirmDialog
      • wijjit.elements.modal.TextInputDialog
        • TextInputDialog
    • Supporting types
      • wijjit.elements.display.contentview.ContentType
        • ContentType
      • wijjit.elements.display.notification.NotificationSeverity
        • NotificationSeverity
      • wijjit.elements.display.tabbed_panel.TabPosition
        • TabPosition
      • wijjit.elements.display.tree.TreeIndicatorStyle
        • TreeIndicatorStyle
  • Template Tags API
    • Layout tags
      • wijjit.tags.layout.VStackExtension
        • VStackExtension
      • wijjit.tags.layout.HStackExtension
        • HStackExtension
      • wijjit.tags.layout.FrameExtension
        • FrameExtension
      • wijjit.tags.layout.GridExtension
        • GridExtension
      • wijjit.tags.layout.ColspanExtension
        • ColspanExtension
      • wijjit.tags.layout.RowspanExtension
        • RowspanExtension
      • wijjit.tags.layout.SplitPanelExtension
        • SplitPanelExtension
    • Input tags
      • wijjit.tags.input.TextInputExtension
        • TextInputExtension
      • wijjit.tags.input.TextAreaExtension
        • TextAreaExtension
      • wijjit.tags.input.CodeEditorExtension
        • CodeEditorExtension
      • wijjit.tags.input.ButtonExtension
        • ButtonExtension
      • wijjit.tags.input.CheckboxExtension
        • CheckboxExtension
      • wijjit.tags.input.CheckboxGroupExtension
        • CheckboxGroupExtension
      • wijjit.tags.input.RadioExtension
        • RadioExtension
      • wijjit.tags.input.RadioGroupExtension
        • RadioGroupExtension
      • wijjit.tags.input.SelectExtension
        • SelectExtension
      • wijjit.tags.input.SliderExtension
        • SliderExtension
      • wijjit.tags.input.ToggleExtension
        • ToggleExtension
      • wijjit.tags.input.DataGridExtension
        • DataGridExtension
    • Display tags
      • wijjit.tags.display.TextExtension
        • TextExtension
      • wijjit.tags.display.TableExtension
        • TableExtension
      • wijjit.tags.display.TreeExtension
        • TreeExtension
      • wijjit.tags.display.ProgressBarExtension
        • ProgressBarExtension
      • wijjit.tags.display.SpinnerExtension
        • SpinnerExtension
      • wijjit.tags.display.ContentViewExtension
        • ContentViewExtension
      • wijjit.tags.display.LogViewExtension
        • LogViewExtension
      • wijjit.tags.display.ListViewExtension
        • ListViewExtension
      • wijjit.tags.display.StatusBarExtension
        • StatusBarExtension
      • wijjit.tags.display.StatusIndicatorExtension
        • StatusIndicatorExtension
      • wijjit.tags.display.LinkExtension
        • LinkExtension
      • wijjit.tags.display.ImageViewExtension
        • ImageViewExtension
      • wijjit.tags.display.PageExtension
        • PageExtension
      • wijjit.tags.display.PagerExtension
        • PagerExtension
      • wijjit.tags.display.TabExtension
        • TabExtension
      • wijjit.tags.display.TabbedPanelExtension
        • TabbedPanelExtension
      • wijjit.tags.display.ModalExtension
        • ModalExtension
    • Chart tags
      • wijjit.tags.charts.SparklineExtension
        • SparklineExtension
      • wijjit.tags.charts.BarChartExtension
        • BarChartExtension
      • wijjit.tags.charts.ColumnChartExtension
        • ColumnChartExtension
      • wijjit.tags.charts.LineChartExtension
        • LineChartExtension
      • wijjit.tags.charts.GaugeExtension
        • GaugeExtension
      • wijjit.tags.charts.HeatMapExtension
        • HeatMapExtension
    • Dialogs & menus
      • wijjit.tags.dialogs.ConfirmDialogExtension
        • ConfirmDialogExtension
      • wijjit.tags.dialogs.AlertDialogExtension
        • AlertDialogExtension
      • wijjit.tags.dialogs.TextInputDialogExtension
        • TextInputDialogExtension
      • wijjit.tags.menu.MenuItemExtension
        • MenuItemExtension
      • wijjit.tags.menu.DropdownExtension
        • DropdownExtension
      • wijjit.tags.menu.ContextMenuExtension
        • ContextMenuExtension
    • Item tags
      • wijjit.tags.input.SelectItemExtension
        • SelectItemExtension
      • wijjit.tags.display.TreeItemExtension
        • TreeItemExtension
  • Terminal API
    • ANSI helpers
      • wijjit.terminal.ansi.ANSIColor
        • ANSIColor
      • wijjit.terminal.ansi.ANSIStyle
        • ANSIStyle
      • wijjit.terminal.ansi.ANSICursor
        • ANSICursor
      • wijjit.terminal.ansi.ANSIScreen
        • ANSIScreen
      • wijjit.terminal.ansi.visible_length
        • visible_length()
      • wijjit.terminal.ansi.wrap_text
        • wrap_text()
      • wijjit.terminal.ansi.clip_to_width
        • clip_to_width()
      • wijjit.terminal.ansi.strip_ansi
        • strip_ansi()
      • wijjit.terminal.ansi.colorize
        • colorize()
    • Input & mouse
      • wijjit.terminal.input.KeyType
        • KeyType
      • wijjit.terminal.input.Key
        • Key
      • wijjit.terminal.input.Keys
        • Keys
      • wijjit.terminal.input.InputHandler
        • InputHandler
      • wijjit.terminal.mouse.MouseEvent
        • MouseEvent
      • wijjit.terminal.mouse.MouseEventType
        • MouseEventType
      • wijjit.terminal.mouse.MouseButton
        • MouseButton
      • wijjit.terminal.mouse.MouseTrackingMode
        • MouseTrackingMode
      • wijjit.terminal.mouse.MouseEventParser
        • MouseEventParser
    • Screen & buffers
      • wijjit.terminal.screen.ScreenManager
        • ScreenManager
      • wijjit.terminal.screen.alternate_screen
        • alternate_screen()
      • wijjit.terminal.cell.Cell
        • Cell
      • wijjit.terminal.cell.CellPool
        • CellPool
      • wijjit.terminal.screen_buffer.ScreenBuffer
        • ScreenBuffer
      • wijjit.terminal.screen_buffer.DiffRenderer
        • DiffRenderer
  • Rendering API
    • Key classes
      • wijjit.rendering.paint_context.PaintContext
        • PaintContext
      • wijjit.rendering.ansi_adapter.ansi_string_to_cells
        • ansi_string_to_cells()
      • wijjit.rendering.ansi_adapter.cells_to_ansi
        • cells_to_ansi()
  • Styling API
    • Overview
      • Key style classes
    • Key classes
      • wijjit.styling.style.Style
        • Style
      • wijjit.styling.resolver.StyleResolver
        • StyleResolver
      • wijjit.styling.theme.Theme
        • Theme
      • wijjit.styling.theme.DefaultTheme
        • DefaultTheme
      • wijjit.styling.theme.ThemeManager
        • ThemeManager
  • Helpers API
    • wijjit.helpers.load_filesystem_tree
      • load_filesystem_tree()

Examples

  • Examples
    • Running an example
    • Basics & essentials
    • Inline rendering
    • Widgets & components
    • Advanced workflows
    • Where to next
  • Cookbook
    • Form validation with inline errors
    • Persisting data between sessions
    • Multi-view navigation with keyboard shortcuts
    • Background tasks & progress indicators
    • Modal confirmations before destructive actions
    • Data tables with selection
    • Notifications & status feedback
    • Theming and styling tweaks

Developer Guide

  • Architecture
    • Runtime overview
    • Module map
    • Renderer & layout pipeline
    • Virtual DOM & Reconciliation
      • Keying elements inside {% for %} loops
    • Thread-safe RenderContext
    • Ephemeral State Pattern
    • Clip Region System
    • Event system
    • State & wiring
    • Overlays & modals
    • Terminal adapters
    • Extending Wijjit
  • Contributing
    • Environment setup
    • Day-to-day commands
    • Coding standards
    • Commit & PR expectations
    • Review process
    • Communicating changes
    • Need help?
  • Testing
    • Directory layout
    • Quick commands
    • Markers
    • Snapshots & visual tests
    • Writing new tests
    • CI expectations
Wijjit
  • Modal Dialogs & Overlays
  • View page source

Modal Dialogs & Overlays

Wijjit’s overlay system lets you layer modals, dropdowns, context menus, and tooltips above the base UI without rewriting your layout. Everything is coordinated by wijjit.core.overlay.OverlayManager.

Overlay layers

Overlays live in one of several wijjit.core.overlay.LayerType buckets:

  • BASE – normal UI (no overlay).

  • MODAL – blocking dialogs, confirmation flows.

  • DROPDOWN – dropdowns, context menus.

  • TOOLTIP – transient tooltips/popovers.

Each layer has its own z-index range. Within a layer, newly pushed overlays get a higher z-index so they stack correctly.

Showing a modal from a template

The simplest way to show a modal is the {% modal %} tag bound to a state key via visible=. The modal renders only while that state key is truthy, and you flip it from action handlers:

from wijjit import Wijjit, render_template_string

app = Wijjit()
app.state["show_confirm"] = False

@app.view("home", default=True)
def home():
    return render_template_string("""
        {% vstack %}
          {% button action="open" %}Delete project{% endbutton %}

          {% modal id="confirm" visible="show_confirm" title="Delete project?" width=44 height=9 %}
            This cannot be undone.

            {% hstack spacing=2 %}
              {% button action="confirm_cancel" %}Cancel{% endbutton %}
              {% button action="confirm_delete" variant="danger" %}Delete{% endbutton %}
            {% endhstack %}
          {% endmodal %}
        {% endvstack %}
        """)

@app.on_action("open")
def open_modal(event):
    app.state["show_confirm"] = True

@app.on_action("confirm_cancel")
def cancel(event):
    app.state["show_confirm"] = False

@app.on_action("confirm_delete")
def delete(event):
    # ... perform deletion ...
    app.state["show_confirm"] = False

The {% modal %} tag accepts id, visible (state key for visibility), title, width, height, and border (single, double, rounded). Focus trapping and a dimmed background are applied automatically for modal-layer overlays.

Creating overlays programmatically

The app exposes one-call helpers that build the overlay entry for you and return the Overlay handle:

  • app.show_modal(element, on_close=None, dim_background=True, close_on_escape=True, close_on_click_outside=False) – focus-trapping modal on the MODAL layer.

  • app.show_dropdown(element, x, y, on_close=None, close_on_click_outside=True, close_on_escape=True) – positioned dropdown on the DROPDOWN layer.

  • app.show_tooltip(element, x, y, close_on_click_outside=True) – transient tooltip on the TOOLTIP layer (see Mouse Support).

from wijjit.elements.display.modal import ModalElement

def show_confirm():
    modal = ModalElement(title="Delete project?", width=44, height=9, border_style="rounded")
    overlay = app.show_modal(modal, on_close=lambda: app.state.update({"dirty": False}))

For full control — custom layer, z-index, or dim behaviour — you can instead instantiate a wijjit.elements.display.modal.ModalElement and push it onto the overlay manager yourself:

from wijjit.core.overlay import LayerType
from wijjit.elements.display.modal import ModalElement

def show_confirm():
    modal = ModalElement(
        title="Delete project?",
        width=44,
        height=9,
        border_style="rounded",
    )
    app.overlay_manager.push(
        modal,
        layer_type=LayerType.MODAL,
        trap_focus=True,
        dimmed_background=True,
    )

ModalElement itself is just a bordered container - its constructor params are id, title, width, height, border_style, centered, and padding (there is no body or buttons argument; add child elements via the layout tree, or prefer the {% modal %} template approach above for button-bearing dialogs).

OverlayManager.push returns an Overlay object you can keep to close manually. Options:

  • close_on_click_outside – close if the user clicks outside the overlay (default True).

  • close_on_escape – respond to Escape (default True).

  • trap_focus – keep focus inside the overlay until closed (set True for modals).

  • dimmed_background – render a dimmed layer behind the overlay.

  • on_close – callback invoked after the overlay is dismissed.

When trap_focus=True, keyboard navigation (Tab/Shift+Tab) continues to work within the modal, cycling through its focusable elements. Focus is automatically restored to the previously focused element when the modal closes.

A trapping overlay always takes focus somewhere, defaulting to its first focusable element. Mark an element inside the dialog autofocus=True to choose a different one - useful for putting the cursor straight into a TextInputDialog-style prompt, or on the safe button of a destructive confirmation. See Focus Navigation for details.

Templated dialogs

You rarely need to instantiate modals manually. wijjit.tags.dialogs exposes tags tailored to common flows:

{% confirmdialog %}

Renders a confirm/cancel dialog. Attributes: id, visible (state key controlling visibility - required for the dialog to appear), title, message (or supply the message as body content), confirm_action, cancel_action, confirm_label, cancel_label, width, height, border.

{% confirmdialog visible="show_confirm"
                 title="Delete file?"
                 message="This cannot be undone."
                 confirm_action="do_delete"
                 cancel_action="cancel_delete"
                 confirm_label="Delete"
                 cancel_label="Cancel" %}{% endconfirmdialog %}
{% alertdialog %}

Simple “OK” dialog. Attributes: id, visible (required state key), title, message (or body content), ok_action, ok_label, width, height, border.

{% inputdialog %}

Collects a short text input. Attributes: id, visible (required state key), title, prompt, initial_value, submit_action, cancel_action, placeholder, submit_label, cancel_label, width, height, border, input_width.

Each dialog tag is only rendered while its visible state key is truthy, so set that key to True from an action handler to show the dialog and back to False to dismiss it. The renderer turns each tag into the matching dialog overlay element and pushes it automatically. Actions fire like any other button: use @app.on_action("do_delete") to handle the user’s choice.

Dropdowns & context menus

Dropdowns ({% dropdown for="button_id" %}) and context menus ({% contextmenu target="list_item" %}) are implemented in wijjit.tags.menu. They automatically attach to the specified target element, track click/hover coordinates, and close when the user clicks elsewhere. Right-click detection is handled by wijjit.core.mouse_router.MouseEventRouter.

Closing overlays

Ways an overlay can close:

  • User clicks outside (close_on_click_outside).

  • User presses Escape (close_on_escape).

  • An action handler calls app.close_overlay(overlay) — the public counterpart to the show_* helpers — to dismiss the overlay it returned (or app.close_overlay() with no argument to close the topmost). For lower-level control, app.overlay_manager.pop(overlay) closes one overlay and app.overlay_manager.pop_layer(LayerType.MODAL) closes every overlay in a layer.

  • Overlays tied to state (e.g., notifications) update their visible_state_key to False.

When closing, the overlay manager restores the previous focus state so the user returns to the element they were interacting with before the modal opened.

Stacking & multiple overlays

It’s common to have a dropdown inside a modal or a tooltip above a dropdown. Because each layer has its own z-index, you can safely push overlays in any order. Best practices:

  • Keep the overlay stack shallow; nested modals are confusing.

  • Always supply trap_focus=True for modals so keyboard users don’t accidentally interact with the background.

  • Use dimmed_background sparingly (only for blocking dialogs).

Notifications & toasts

Toast-style notifications also use the overlay system under the hood. The easiest entry point is the high-level app.notify() helper, which builds a notification element and queues it for you:

app.notify("Saved successfully", severity="success")
app.notify("Deployment failed", severity="error", duration=None)  # no auto-dismiss

severity is one of "info" (default), "success", "warning", or "error". Pass duration=None for a notification that stays until dismissed, and an optional action=(label, callback) tuple to add an action button. notify() returns a notification id you can pass to app.dismiss_notification(id).

For lower-level control, wijjit.core.notification_manager.NotificationManager exposes add(element, duration=3.0, on_close=None), where element is a wijjit.elements.display.notification.NotificationElement:

from wijjit.elements.display.notification import NotificationElement

note = NotificationElement(message="Saved successfully", severity="success")
app.notification_manager.add(note, duration=3.0)

The manager creates overlay entries at the edge of the viewport and removes them when timers expire or the user dismisses them.

Tips

  • Prepare dialog templates as macros for reuse (e.g., {% macro confirm_delete(name) %}…{% endmacro %}).

  • Centralize overlay actions (confirm_delete, confirm_cancel) in a dedicated module so business logic isn’t scattered across views.

  • Consider storing overlay visibility in state (state.show_settings_modal) if the dialog affects layout or needs to coordinate with other components.

For focus-specific guidance read Focus Navigation; for pointer interactions see Mouse Support.

Previous Next

© Copyright 2025, Tom Villani, Ph.D..

Built with Sphinx using a theme provided by Read the Docs.