Components
Wijjit ships with a wide range of input and display components. They are implemented under wijjit.elements and exposed to templates through wijjit.tags. This section summarizes what’s available and when to reach for each widget.
The examples referenced here are managed under examples/. We pull live snippets with literalinclude so the docs stay in sync with the runnable demos—open the referenced script if you want to try it yourself.
Form inputs
- TextInput / TextArea
Single-line and multi-line editors (
wijjit.elements.input.text). Support placeholder text, max length, width/height control, Enter actions, selection, copy/paste (viapyperclip), and cursor movement. Both emitChangeEventon edits and updatestate[id]automatically. Usebind=Falseto manage the value manually (useful for formatted or derived inputs) and attachaction=...to submit on Enter. To read or write the text from Python, use the.valueproperty — it is available uniformly onTextInput,TextArea, andCodeEditor(assigningelement.value = "..."replaces the content and fireson_change).examples/basic/simple_input_test.py– binding atextinputtostate@app.view("main", default=True) def main_view(): return render_template_string( """ {% vstack width=50 height=10 %} Status: {{ state.test }} {% textinput id="test" placeholder="Type here" width=30 %}{% endtextinput %} Press 'q' (or Ctrl+Q while typing) to quit {% endvstack %} """ )
textareaadds scrollbars, selection APIs, and clipboard shortcuts. It’s ideal for log editing, notes, or prompt composition. Pair it with derived state to show live counts, as demonstrated below.By default Tab moves focus out of a
textarea, as it does in a web form. Setcapture_tab=True(with an optionaltab_width, default 4) to make Tab insert an indent instead;Shift+Tabstill moves focus backward, so the field can always be left. See When Tab belongs to the element instead.textarea(andcodeeditor, which extends it) supports undo with ``Ctrl+Z`` and redo with ``Ctrl+Y``. Typing a word is a single undo rather than one per letter, and a keypress that does several things at once - typing over a selection, or an insertion that triggers a hard-wrap reflow - undoes as one action. History is bounded at 200 edits and is discarded when the content is replaced programmatically (element.value = "..."with different text).undo()andredo()are also callable from Python.Template excerpt fromexamples/widgets/textarea_demo.py"""{% frame height="fill" title="TextArea demo" %} {% textarea id="content" height=10 width=80 show_scrollbar=true border="single" %}{% endtextarea %} Lines: {{ lines }} | Chars: {{ chars }} | Wrap: {{ wrap_display }} [Shift+Arrows] Select [Ctrl+C/X/V] Clipboard [Ctrl+A] Select All [Ctrl+Q] Quit {% endframe %} """,
- CodeEditor
Syntax-highlighted code editor (
wijjit.elements.input.code_editor). ExtendsTextAreawith syntax highlighting powered by Pygments. Supports 500+ programming languages, multiple color themes (monokai, dracula, nord, github-light), line numbers, and automatic language detection.Key attributes:
language- Programming language for highlighting (python,javascript,rust, etc.) or"auto"for detectiontheme- Color theme (monokai,dracula,nord,github-light)show_line_numbers- Display line numbers in the gutter (default:True)filename_hint- Helps auto-detection whenlanguage="auto"capture_tab- Tab inserts an indent rather than moving focus (default:Truehere, unlikeTextArea);tab_widthsets its size (default: 4).Shift+Tabstill steps backward out of the editor - see When Tab belongs to the element instead.
Performance is optimized for large files through per-line token caching and debounced re-tokenization during edits. Inherits all
TextAreafeatures including selection, clipboard support, and scrolling.examples/widgets/code_editor_demo.py- syntax highlighting with theme switching@app.view("main", default=True) def main_view(): """Main view with code editor demo.""" # Initialize state if "language" not in app.state: app.state["language"] = "python" app.state["theme"] = "monokai" app.state["editor"] = PYTHON_CODE return render_template_string( """ {% frame border="rounded" title="CodeEditor Demo - Syntax Highlighting" width=90 height=35 %} {% vstack spacing=1 %} {% hstack spacing=2 %} Language: {% button action="lang_python" %}Python{% endbutton %} {% button action="lang_js" %}JavaScript{% endbutton %} {% button action="lang_rust" %}Rust{% endbutton %} {% endhstack %} {% hstack spacing=2 %} Theme: {% button action="theme_monokai" %}Monokai{% endbutton %} {% button action="theme_dracula" %}Dracula{% endbutton %} {% button action="theme_nord" %}Nord{% endbutton %} {% button action="theme_github" %}GitHub{% endbutton %} {% endhstack %} {% codeeditor id="editor" language=state.language theme=state.theme width=84 height=15 show_line_numbers=True tab_index=0 %} {% endcodeeditor %} {% hstack spacing=2 %} Language: {{ state.language }} | Theme: {{ state.theme }} | Press Ctrl+Q to quit {% endhstack %} {% endvstack %} {% endframe %} """, state=app.state, )
- DataGrid
Spreadsheet-like data entry element (
wijjit.elements.input.datagrid). Implements VisiCalc/Lotus 1-2-3 style editing with an entry line at the top for data input. Supports keyboard navigation (arrow keys, Tab, Enter), mouse interaction (click cells, scroll), and two-way state binding - committed edits are written back tostate[id]. Note that DataGrid normalizes every cell tostr, so the rows it writes back are strings.Key attributes:
data- 2D list of cell values (list of rows)columns- List of column headers (strings or dicts withkey,label,width)width/height- Grid dimensions in charactersshow_row_numbers- Display row numbers on the left (default:True)editable- Allow cell editing (default:True)show_scrollbar- Show scrollbars when content exceeds viewport (default:True)
Navigation:
Arrow keys - Move between cells
Tab / Shift+Tab - Move to next/previous cell
Enter - Confirm edit and move down, or start editing current cell
Escape - Cancel current edit
Mouse click - Select cell, double-click to edit
Mouse scroll - Scroll through large datasets
Data formats (input and output):
List of lists - Default format:
[["A", "B"], ["C", "D"]]List of dicts - Each row as a dict:
[{"name": "John", "age": 30}, ...]pandas DataFrame - Automatically converts to/from DataFrames (pandas optional)
{% datagrid id="spreadsheet" width=60 height=15 %} columns: - {key: "name", label: "Name", width: 20} - {key: "price", label: "Price", width: 10} - {key: "qty", label: "Quantity", width: 10} data: - ["Widget", "9.99", "100"] - ["Gadget", "19.99", "50"] {% enddatagrid %}
Working with DataGrid state:
# Get data as list of lists (default) data = app.state["spreadsheet"] # Get data as list of dicts from wijjit.elements.input.datagrid import DataGrid grid = app.get_element_by_id("spreadsheet") data_as_dicts = grid.get_data_as_dicts() # Get data as pandas DataFrame (if pandas available) df = grid.get_data_as_dataframe() # Set data from various formats grid.set_data([["A", "B"], ["C", "D"]]) # list of lists grid.set_data([{"col1": "A", "col2": "B"}]) # list of dicts grid.set_data(pandas_df) # DataFrame
See
examples/widgets/datagrid_demo.pyfor a complete inventory management example with add/delete row functionality.- Button
Clickable action trigger (
wijjit.elements.input.button). Attributes:action(the action id to emit),style(the bracket preset used to draw the button), and the universalclassfor theming. Style a “danger” button with a CSS class (class="danger") plus a matching theme entry rather than avariantattribute — there is none. Remember thatactionids participate in handler routing—keep them short verbs (save,cancel) and reuse them across views to share behavior.- Checkbox / CheckboxGroup
Toggle booleans or sets of values. Groups accept
optionsand maintain a list in state (state.selected_tags). Support tri-state rendering, keyboard navigation, and spacing options. Use them for preference panes or wizards.examples/widgets/checkbox_demo.py– single inputs + grouped toggles@app.view("main", default=True) def main_view(): """Main form view with checkboxes.""" return render_template_string( """ {% frame title="Checkbox Demo" border="double" width=70 height=28 %} {% vstack spacing=1 padding=1 %} {% vstack spacing=0 %} {{ state.status }} {% endvstack %} {% vstack %} Individual Checkboxes: {% checkbox id="newsletter" label="Subscribe to newsletter" %}{% endcheckbox %} {% checkbox id="terms" label="I agree to the terms and conditions" %}{% endcheckbox %} {% endvstack %} {% vstack spacing=1 %} Email Preferences (Multiple Selection): {% checkbox id="notifications" label="Email notifications" %}{% endcheckbox %} {% checkbox id="updates" label="Product updates" %}{% endcheckbox %} {% checkbox id="marketing" label="Marketing emails" %}{% endcheckbox %} {% endvstack %} {% hstack spacing=2 %} {% button action="submit" %}Submit{% endbutton %} {% button action="reset" %}Reset{% endbutton %} {% button action="quit" %}Quit{% endbutton %} {% endhstack %} {% if state.submitted %} Submitted Values: Newsletter: {{ 'Yes' if state.newsletter else 'No' }} Terms Accepted: {{ 'Yes' if state.terms else 'No' }} Email Preferences: {% if state.notifications or state.updates or state.marketing %} {% if state.notifications %}- Email notifications{% endif %} {% if state.updates %}- Product updates{% endif %} {% if state.marketing %}- Marketing emails{% endif %} {% else %} None selected {% endif %} {% endif %} {% vstack spacing=0 %} Controls: [Tab/Shift+Tab] Navigate | [Space] Toggle | [q] Quit {% endvstack %} {% endvstack %} {% endframe %} """ )
- Radio / RadioGroup
Mutually exclusive selection. Layout horizontally or vertically, optionally wrap inside a
framewithlegend="…". Combine withstate.watchto react when users pick a new option.- Select
Drop-down picker with search/filter ability. Accepts dictionaries or tuples, can render icons next to labels, and integrates with dropdown overlays for large option sets.
- Link
Inline clickable text element (
wijjit.elements.display.link). Renders as styled text that can be focused and activated via keyboard (Enter/Space) or mouse click. Perfect for inline navigation, action triggers, or any clickable text that shouldn’t look like a button.Key attributes:
action- Action name to trigger when clickedclass- CSS class for styling (e.g.,text-danger,text-success)
{% hstack spacing=3 %} {% link action="home" %}Home{% endlink %} {% link action="settings" %}Settings{% endlink %} {% link action="logout" class="text-danger" %}Logout{% endlink %} {% endhstack %}
See
examples/widgets/contentview_demo.pyfor links used alongside HTML-formatted content.- Slider
Numeric input with draggable handle (
wijjit.elements.input.slider). Supports both integer and float modes, keyboard navigation (Left/Right arrows, Home/End), and mouse interaction (click to set, drag to adjust).Key attributes:
min- Minimum value (default: 0)max- Maximum value (default: 100)value- Initial value (defaults to min)step- Increment for keyboard navigation (default: 1)width- Track width in characters (default: 20)float_mode- Return float instead of int (default:False)label- Optional label before slidershow_value- Display current value after slider (default:True)
{# Integer slider #} {% slider id="volume" min=0 max=100 value=50 %}{% endslider %} {# Float slider with decimal step #} {% slider id="opacity" min=0.0 max=1.0 step=0.1 float_mode=True label="Opacity" %}{% endslider %}
See
examples/widgets/slider_demo.pyfor integer and float slider examples.- Toggle
Boolean switch with visual indicator (
wijjit.elements.input.toggle). Provides clearer on/off feedback than a checkbox with colored block characters. Supports single label mode (label after switch) and dual label mode (labels on both sides).Key attributes:
checked- Initial state (default:False)label- Label text for single modelabel_mode-single(default) ordualon_label- “On” text for dual mode (default: “ON”)off_label- “Off” text for dual mode (default: “OFF”)
Colors are themeable via CSS:
toggle.on,toggle.off,toggle:focus.{# Single mode: switch + label #} {% toggle id="dark_mode" label="Dark Mode" %}{% endtoggle %} {# Dual mode: OFF [switch] ON #} {% toggle id="theme" label_mode="dual" off_label="Light" on_label="Dark" %}{% endtoggle %}
See
examples/widgets/toggle_demo.pyfor single and dual mode examples.
Special behaviors:
bind=Falselets you manage the value manually (useful for derived or formatted inputs), andbind="some_key"binds to that state key instead of the id - so two widgets can share one key, and an id need not colonize one. See The bind attribute.actionon inputs triggers when Enter is pressed.With
bind=Truetheidis the state key (except forradio/radiogroup, which key off the groupname). Wijjit auto-generates ids, but naming them yourself keeps focus/state debugging easier.autofocus=Trueputs the cursor in this element when the app starts. Without it nothing is focused and the user must press Tab before typing does anything - see Initial focus: the autofocus attribute. Use it on one element per view.
Display widgets
- ContentView
Unified content display element supporting multiple content types (
wijjit.elements.display.contentview). Renders content in various formats with scrolling, borders, and keyboard/mouse navigation. This single component replaces the need for separate markdown, code, and HTML viewers.Supported content types (
content_typeattribute):"plain"/"text"- Plain text with word wrapping"ansi"- Text with ANSI escape codes passed through"html"- HTML-like markup with<b>,<i>,<u>,<s>, and<style>tags"markdown"- Markdown with headings, lists, code blocks, and blockquotes"rich"- Rich markup with[bold],[red], etc."code"- Syntax-highlighted code (500+ languages via Pygments)
Key attributes:
content_type- Content format (default:"plain")width/height- Display dimensionsborder- Border style:single,double,rounded, ornonetitle- Optional title in top bordershow_scrollbar- Show vertical scrollbar (default:True)
Code-specific attributes:
language- Programming language for syntax highlighting (default:"python")theme- Syntax highlighting theme (default:"monokai")show_line_numbers- Display line numbers (default:False)line_number_start- Starting line number (default:1)
{# Markdown content #} {% contentview id="docs" content_type="markdown" title="Documentation" height=15 %} # Welcome This is **bold** and *italic* text. - Bullet points - Multiple items {% endcontentview %} {# Syntax-highlighted code #} {% contentview id="code" content_type="code" language="python" show_line_numbers=true title="Example" %} def hello(name: str) -> str: return f"Hello, {name}!" {% endcontentview %} {# HTML-style formatting #} {% contentview id="html" content_type="html" title="Styled Text" %} <b>Bold</b> and <i>italic</i> <style fg="red">Red text</style> {% endcontentview %}
Keyboard controls: Up/Down arrows for line-by-line scrolling, PageUp/PageDown for page scrolling, Home/End to jump to start/end.
See
examples/widgets/contentview_demo.pyfor a complete demonstration of all content types.- Table
Feature-rich table control with column sizing, alignment, zebra striping, sorting, and optional selection/highlighting. Works well for log viewers, data dashboards, and admin lists. Consider pairing with scrollable frames for large datasets or binding button actions to operate on selected rows. Assign
table.data = rowsto swap the contents reactively — it re-applies any active sort and re-clamps scroll, staying in sync (do not mutate the underlying list in place).examples/widgets/table_demo.py– sorted table with action bar@app.view("main", default=True) def main_view(): """Main view showcasing table element.""" return render_template_string( """ {% frame title="Table Demo - User Directory" border="double" width=100 height=29 %} {% vstack spacing=1 padding=1 %} {% vstack spacing=0 %} {{ state.message }} {% endvstack %} {% vstack spacing=0 %} Instructions: Press TAB to focus table | Use Up/Down/PageUp/PageDown to scroll | Mouse wheel also works | Press 'q' to quit {% endvstack %} {% table id="users" data=state.users columns=["name", "email", "status", "age"] sortable=true width=94 height=19 show_header=true show_scrollbar=true border="single" %} {% endtable %} {% hstack spacing=2 %} {% button id="add_user_btn" action="add_user" %}Add User{% endbutton %} {% button id="clear_btn" action="clear_table" %}Clear Table{% endbutton %} {% button id="reset_btn" action="reset_table" %}Reset Table{% endbutton %} {% button id="quit_btn" action="quit" %}Quit{% endbutton %} {% endhstack %} {% endvstack %} {% endframe %} """ ) # noqa: E501
- Tree
Hierarchical explorer for file systems, menus, or org charts. Nodes can be expanded/collapsed via keyboard or mouse. See
examples/widgets/tree_demo.pyfor layout variations.- ListView
Scrollable vertical list that highlights the selected row. Great for menus, chat transcripts, or search results. Works nicely with
app.on_actionhandlers that parse the row id (row_selected_<id>pattern).- LogView
Tail-like streaming buffer with manual/auto-scroll toggles. Supports severity coloring and timestamp columns. Pair it with background tasks to watch long-running jobs. Assign
logview.lines = [...](or the equivalentset_lines(...)) to replace the buffer reactively — it re-renders, re-clamps scroll, and honours auto-scroll. To append, reassign with the new list (logview.lines = logview.lines + [entry]).- StatusIndicator
Colored status indicator with extensible presets (
wijjit.elements.display.status_indicator). Displays a colored circle (or other shape) to indicate status. Non-interactive display element perfect for dashboards and system status displays.Built-in statuses:
error(red),warning(yellow),success(green),info(blue),pending(cyan),active(bright green),inactive(dim),disabled(gray).Key attributes:
status- Status name (default:info)label- Optional label text after indicatorindicator_style- Shape:filled(default),hollow,square,asciicustom_statuses- Dict to add/override status colors
{# Built-in statuses #} {% status status="success" label="Connected" %}{% endstatus %} {% status status="error" label="Failed" %}{% endstatus %} {% status status="warning" label="Degraded" %}{% endstatus %} {# Custom status with color #} {% status status="processing" custom_statuses={"processing": "magenta"} label="Working..." %}{% endstatus %} {# Different indicator styles #} {% status status="info" indicator_style="hollow" label="Hollow" %}{% endstatus %} {% status status="info" indicator_style="square" label="Square" %}{% endstatus %}
See
examples/widgets/status_indicator_demo.pyfor a complete dashboard example.- ProgressBar / Spinner
Progress indicators for background tasks.
progressbaraccepts numericvalueand optionallabel;spinneranimates automatically if you setapp.refresh_interval.ProgressBar supports multiple display and visual styles:
Display styles (
styleattribute):filled(default),percentage,gradient,customBar styles (
bar_styleattribute): Visual presets for the progress bar charactersblock(default) - Solid Unicode block charactersthin- Thin horizontal linethick- Heavy horizontal lineequals- Classic====stylearrow- Arrow/chevron>>>>styledots- Bullet dot charactersascii- Pure ASCII (#and-)hash- Hash marks with spacespipe- Pipe characterssquare- Square box characters
Example with different bar styles:
{% progressbar id="download" value=state.progress bar_style="equals" color="green" %}{% endprogressbar %} {% progressbar id="upload" value=state.upload bar_style="arrow" style="gradient" %}{% endprogressbar %} {% progressbar id="cpu" value=state.cpu bar_style="thin" %}{% endprogressbar %}
See
examples/widgets/progress_demo.pyfor a complete demonstration of all bar styles.- StatusBar
Sticky footer for breadcrumbs, key hints, or status indicators. Combine with
{% hstack %}sections to align regions left/center/right.examples/widgets/statusbar_demo.pyshows how to surface view-scoped hints.- Notifications
Toast banners styled by
severity(info,success,warning,error). There is no{% notification %}template tag — raise one from Python withapp.notify("Saved!", severity="success"), which routes throughwijjit.core.notification_manager.NotificationManagerand auto-dismisses afterdurationseconds (passduration=Noneto keep it up). Use them for asynchronous feedback or confirmations.examples/widgets/notification_demo.py– framing actionable hints@app.view("main", default=True) def main_view(): return render_template_string( """ {% vstack %} {% frame border="double" title="Notification System Demo" %} Welcome to the Notification Demo! Press keys to trigger different notifications: [1] Success notification [2] Error notification [3] Warning notification [4] Info notification [5] Notification with action button [6] Persistent notification (manual dismiss) [7] Notification with bell sound [8] Multiple notifications (stack test) [9] Clear all notifications Press Ctrl+Q to quit --- Active notifications: {{ state.active_count or 0 }} Total shown: {{ state.total_shown or 0 }} {% endframe %} {% endvstack %} """ )
- ImageView
Renders raster images as ASCII/ANSI art in the terminal (
wijjit.elements.display.image). Requires theimagesextra (pip install wijjit[images]), which pulls in Pillow. Exposed via the{% imageview %}tag (registered alias:Image). Accepts a file path, raw bytes, or a PILImageassrcand auto-binds it tostate[id]unlessbind=False.Key attributes:
src- Image source: file path, bytes, or PILImagewidth/height- Size spec: int,"auto","fill", or"50%"(default:"auto")mode- Render mode:"color","quadrant", or"braille"(default:"color")threshold- Braille binarization cutoff:0-255, or"auto"for Otsu’s method (default:"auto")invert- Invert the threshold in braille mode (default:False)background- Background RGB tuple for transparent pixels (default:(0, 0, 0))
The three modes trade colour against spatial detail:
Mode
Subpixels
Colour
Notes
"color"1x2
full
Half-blocks (U+2580). The safe default.
"quadrant"2x2
full
Quadrant blocks (U+2596-U+259F). Two colours per cell, full cell coverage. Usually the best choice for photographs.
"braille"2x4
none
Braille dots (U+2800-U+28FF). Highest subpixel resolution, but monochrome, and the dots only partially cover each cell. Best for line art and high-contrast graphics.
Note
Denser full-coverage character sets exist - sextants (2x3, Unicode 13) and octants (2x4, Unicode 16) - but they are missing from common terminal fonts, including Cascadia Mono, the Windows Terminal default. Wijjit deliberately sticks to character sets that render everywhere.
{% imageview id="logo" src="assets/logo.png" width=40 %}{% endimageview %} {% imageview src="photo.jpg" width=40 mode="quadrant" %}{% endimageview %} {% imageview src="diagram.png" mode="braille" threshold=140 %}{% endimageview %}
Data Visualization
Wijjit includes a suite of data visualization components for dashboards, monitoring, and analytics. All chart elements support reactive updates - simply update the data and the chart re-renders automatically. These are provided by wijjit.elements.display and exposed via wijjit.tags.charts.
- Sparkline
Compact inline trend visualization (
wijjit.elements.display.sparkline). Perfect for embedding trends alongside text or in dense dashboards. Renders in a single row using braille characters for high resolution.Key attributes:
data- List of numeric valueswidth- Display width in characters (default: 20)style- Rendering style:line(braille),bar, ordotshow_current- Display the last value as textshow_minmax- Mark min/max points
{% sparkline data=cpu_history width=30 style="line" show_current=True %}{% endsparkline %}
- BarChart
Horizontal bar chart with labels (
wijjit.elements.display.barchart). Supports scrolling for large datasets, gradient or threshold-based coloring, and value display.Key attributes:
data- List of values, tuples(label, value), or dicts{"label": ..., "value": ...}width/height- Display dimensionsshow_values- Display numeric values on barscolor_mode- Color mode:default,gradient, orthresholdmax_value- Override automatic scaling
{% barchart data=sales_by_region width=40 height=8 show_values=True color_mode="gradient" %}{% endbarchart %}
- ColumnChart
Vertical column chart with Y-axis (
wijjit.elements.display.columnchart). Uses block characters for rendering with optional grid lines and axis labels.Key attributes:
data- List of values or labeled datawidth/height- Display dimensionsshow_axis- Display Y-axis with tick marksshow_labels- Display X-axis labelscolor_mode- Color mode for columns
{% columnchart data=monthly_revenue width=50 height=12 show_axis=True show_labels=True %}{% endcolumnchart %}
- LineChart
High-resolution line chart using braille characters (
wijjit.elements.display.linechart). Each character contains a 2x4 dot grid, enabling smooth curves in terminal displays. Supports multiple series, area fills, and axis display.Key attributes:
data- List of values or list of series[{"values": [...], "label": ...}, ...]width/height- Display dimensionsstyle- Rendering style:line,area, ordotsshow_axis- Display axes with labelsshow_legend- Display series legend (for multi-series)
{% linechart data=temperature_readings width=60 height=15 style="line" show_axis=True %}{% endlinechart %}
- Gauge
Value indicator with linear or arc styles (
wijjit.elements.display.gauge). Ideal for showing percentages, metrics, or bounded values with threshold coloring.Key attributes:
value- Current valuemin_value/max_value- Value range (default: 0-100)style- Display style:linear(horizontal bar) orarc(semi-circular)color_mode- Color mode:default,gradient, orthresholdlabel- Optional label text above gaugeunit- Unit suffix for value display (e.g.,%,MB)show_value- Display current valueshow_minmax- Display min/max labels
{% gauge value=cpu_usage style="arc" label="CPU" unit="%" color_mode="threshold" %}{% endgauge %}
- HeatMap
2D grid visualization with color intensity (
wijjit.elements.display.heatmap). Uses block characters with RGB coloring to represent values. Great for correlation matrices, activity grids, or geographic data.Key attributes:
data- 2D list of values[[row1...], [row2...], ...]width/height- Display dimensionscolor_scale- Color palette:viridis,plasma,inferno,cool,hot,greens,blues,redsshow_values- Display values in cells (space permitting)row_labels/col_labels- Optional axis labels
{% heatmap data=correlation_matrix width=40 height=20 color_scale="viridis" %}{% endheatmap %}
All chart elements support reactive updates through state binding:
@app.on_action("refresh")
async def refresh_data(event):
app.state.update({
"cpu_history": await fetch_cpu_metrics(),
"memory_usage": await get_memory_percent()
})
# Charts automatically re-render with new data
See examples/widgets/charts_demo.py for a complete interactive demonstration of all chart types.
Container widgets
- TabbedPanel
Tabbed container for organizing content into switchable panels (
wijjit.elements.display.tabbed_panel). Each tab displays a separate frame of content, with keyboard and mouse navigation between tabs. Ideal for settings panels, multi-page forms, or dashboards with distinct sections.Key attributes:
tab_position- Position of tabs:top(default),bottom,left,rightwidth/height- Panel dimensionsborder- Border style:single(default),double,roundedactive_tab_index- Initially active tab (default: 0)
Navigation:
Horizontal tabs (top/bottom): Left/Right arrows switch tabs
Vertical tabs (left/right): Up/Down arrows switch tabs
Mouse: Click on tab labels to switch
Content scrolling: Up/Down/PageUp/PageDown scroll the active tab’s content
State persistence: The active tab index is automatically saved to
state[id](whereidis the element’s id attribute), preserving the user’s tab selection across re-renders.{% tabbedpanel id="settings" tab_position="top" width=60 height=20 %} {% tab label="General" %} General settings content here... {% checkbox id="dark_mode" label="Dark Mode" %}{% endcheckbox %} {% checkbox id="notifications" label="Enable Notifications" %}{% endcheckbox %} {% endtab %} {% tab label="Advanced" %} Advanced settings content here... {% textinput id="api_key" placeholder="API Key" width=40 %}{% endtextinput %} {% endtab %} {% tab label="About" %} Application version 1.0.0 Built with Wijjit {% endtab %} {% endtabbedpanel %}
See
examples/widgets/tabbedpanel_demo.pyfor a complete interactive demonstration with all tab positions.- Pager
Paged container that shows one
{% page %}at a time with built-in navigation (wijjit.elements.display.pager). Useful for wizards, slideshows, onboarding flows, or any sequential multi-step UI. Each child{% page %}is a self-contained frame; the pager renders a “Page X of Y” indicator and Prev/Next controls.Key attributes:
nav_position- Position of navigation controls:top,bottom(default), orbothshow_indicator- Show the “Page X of Y” indicator (default:True)show_titles- Show the page title in the indicator (default:False)loop- Wrap from the last page back to the first (default:False)current_page- State key name for page binding, or an initial page index (default:0)width/height- Pager dimensions (default: 60 x 20)border- Border style:single(default),double,rounded,none
{% pager id="wizard" nav_position="bottom" show_indicator=True %} {% page title="Welcome" %} Welcome to the setup wizard. {% endpage %} {% page title="Account" %} {% textinput id="username" placeholder="Username" width=30 %}{% endtextinput %} {% endpage %} {% page title="Done" %} All set! {% endpage %} {% endpager %}
Custom components
When the built-in set isn’t enough, implement a subclass of wijjit.elements.base.Element:
Override
render_toto paint into thewijjit.rendering.paint_context.PaintContext.Implement
get_intrinsic_sizeif you need better sizing hints.Set
focusableand implementhandle_key/handle_mousewhen appropriate.Expose the component via a Jinja extension (see
wijjit/tags) or instantiate it inside a view and insert it into the layout tree manually.
Shipping an element as its own package
You do not have to fork Wijjit or monkeypatch it. wijjit.register_element()
couples a VNode type name with your Element subclass and, optionally, a
{% tag %} extension:
from wijjit import Element, register_element
class SparkGauge(Element):
...
register_element("SparkGauge", SparkGauge, tag="sparkgauge")
Because both the element registry and the Jinja environment are built per
renderer, every new renderer drains this global registry at construction — so
the running app and wijjit validate pick your element up automatically.
Call it at module level and declare a wijjit.plugins entry point (mirroring
the pytest11 precedent) and an installed package registers itself on import:
[project.entry-points."wijjit.plugins"]
sparkgauge = "my_package.elements"
Wijjit.register_element is the instance-method form, which also live-patches
an already-constructed app. Scope note: v1 covers leaf elements (self-closing
or simple-body widgets); custom containers, which need layout-tree-builder and
validator integration, are a deferred follow-up.
examples/advanced/plugin_element.py is a complete working example in about
30 lines.
Tips
Wrap inputs inside frames or stacks to control spacing and provide labels.
Use
stateto drive visual states through the universalclassattribute (e.g.,{% button class=state.in_progress and "busy" or "primary" %}), then style those classes in your theme.For high-frequency components (logs, tables), prefer incremental updates to state rather than rebuilding entire datasets every tick.
Read the example gallery – most widgets live under
examples/widgets/*_demo.pyso you can run the exact code showcased here.
Next: learn how to orchestrate modals and overlays in Modal Dialogs & Overlays, then deep dive into interaction layers with Focus Navigation and Mouse Support.