Skip to main content

PySide6DOM v0.3.8

Bring the simplicity of the Web DOM to Python PySide6 Desktop Applications.

Installation

pip install pyside6dom

Upgrade:

pip install --upgrade pyside6dom

PySide6DOM Tutorials:

Tutorials


PySide6DOM bridges the gap between web development and systems programming. It wraps the raw power of the PySide6 (C++/Qt) rendering engine inside the familiar, intuitive Document Object Model (DOM) paradigm used by JavaScript and HTML.

If you know how to build a web page using createElement (ce), getElementById (ge), and append (ba), you already know how to build high-performance, standalone Python desktop applications.

🌟 Why Use PySide6DOM?

  • Zero HTML Parsing: This is not a web view or a browser wrapper. It generates native C++/Qt desktop widgets using Python, ensuring maximum performance.
  • Familiar Syntax: Uses lightweight helper functions modeled directly after the web DOM (ce() for create element, ge() for get element, ba() for body append).
  • Rapid Prototyping: Build user interfaces in seconds without getting bogged down in complex object-oriented boilerplate.
  • Educational Bridge: The perfect stepping stone for web developers transitioning into local hardware control, computer vision, and systems engineering.

🚀 The Code: Web Logic meets Python Power

Look how clean and intuitive building a native desktop app becomes. No complex classes, no confusing layout managers - just straightforward DOM logic.

from pyside6dom import *

# Initialize the Application
init_window("Telemetry Station", 440, 520)

# Create a Header (createElement)
header = ce("text")
header.id = "main_heading"
header.textContent = "Telemetry Link Online"
header.style("font-size: 18px; font-weight: bold; margin-bottom: 10px;")
ba(header) # (appendChild)

welcomeMessage = ce('text')
welcomeMessage.textContent = 'Welcome'
ba(welcomeMessage)

# Create an Input Field
command_input = ce("input")
command_input.id = "user_input"
command_input.placeholder = "Enter station parameter..."
ba(command_input)

# Create an Interactive Button
submit_btn = ce("button")
submit_btn.textContent = "Transmit Command"

# Define what happens on click
def handle_click():
    txt = ge("user_input").value
    welcomeMessage.textContent = txt
    print(f"Transmitting Data: {txt}")

submit_btn.onclick = handle_click
ba(submit_btn)

# Launch the App
run_app()

📖 API Reference

Core Engine Functions

  • init_window(title, width, height): Initializes the main window and layout.
  • run_app(): Starts the Qt application event loop.
  • ce(tag): (document.createElement) Creates a native widget wrapped as a DOMElement.
  • ge(id): (document.getElementById) Retrieves a previously created element by its .id.
  • ba(child, parent=None): (appendChild) Appends an element to the main window or a parent container.
  • set_theme(css) or set_global_style(css): Applies a universal CSS stylesheet to the entire application.
  • setInterval(callback, ms): Repeatedly runs a callback at the specified millisecond interval.
  • cl(*args) or console.log(*args): Logs output to the console, mirroring web debugging.

Supported Tags & Widget Bindings

  • text / p / h1 / span: Text labels.
    • Properties: .textContent, .innerHTML
  • button: Standard push button.
    • Properties: .textContent, .onclick
  • input: Single-line text input field.
    • Properties: .value, .placeholder, .oninput
  • textarea: Multi-line text edit area.
    • Properties: .value, .placeholder, .oninput
  • slider: Numeric range slider.
    • Properties: .value, .oninput
  • checkbox: Toggle checkbox.
    • Properties: .checked, .textContent, .oninput
  • select / dropdown: Dropdown selection menu.
    • Properties: .options (list), .value (selected text), .oninput
  • img: Image display element with Aspect Ratio
    • Properties: .src (file path)
  • video: Video display element with Aspect Ratio
  • div: Standard container widget for grouping elements.
  • scroll_div: Scrollable container area for overflow content.
  • CSS keywords: div, text, button, scroll_div, select, option,

Universal Properties & Methods

All elements support the following properties:

  • .id: Unique string identifier for retrieval with ge(id).
  • .style("css_string"): Inline CSS styling targeting the specific element.

🎨 CSS Styling & Tag Mapping

The engine translates standard HTML tags into PySide6 widgets behind the scenes. This allows you to write clean, web-style CSS for your desktop applications.

(Note: If you are already a PySide6 veteran, standard Qt class names like QPushButton will still work perfectly!)

Layout & Containers

  • bodyQMainWindow (and central widget)
  • divQWidget
  • scroll_divQScrollArea

Text & Media

  • text, h1, p, span, imgQLabel

Interactive Controls

  • buttonQPushButton
  • inputQLineEdit
  • textareaQPlainTextEdit
  • checkboxQCheckBox
  • sliderQSlider
  • select (or dropdown) ➔ QComboBox
  • select optionQComboBox QAbstractItemView (The dropdown list items)

CSS Properties

  • font-colorcolor

pyside6dom Created by Christopher Andrew Topalian

College of Scripting Music & Science

Disclaimer: This is an independent open-source educational project. "PySide" and "Qt" are registered trademarks of The Qt Company. This project is not affiliated with, endorsed by, or sponsored by The Qt Company.


COMMON COMMANDS:

Install:

pip install pyside6dom

Upgrade:

pip install --upgrade pyside6dom


Example
# pyside6dom_example.py

# after we have installed pyside6dom using
# pip install pyside6dom

from pyside6dom import *

# Initialize the Application
init_window("PySide6DOM Feature Showcase", 450, 650)

# Worldwide Header
header = ce("h1")
header.textContent = "🚀 Mission Control"
header.style("font-size: 24px; color: #00ffcc; font-weight: bold; margin-bottom: 20px;")
ba(header)

# Text Input with Real-Time 'oninput' Event
pilot_input = ce("input")
pilot_input.id = "pilot_name"
pilot_input.placeholder = "Enter Pilot Name..."
pilot_input.style("padding: 10px; font-size: 14px; border: 2px solid #555; border-radius: 5px;")
ba(pilot_input)

# Live feedback label for the input
typing_echo = ce("text")
typing_echo.id = "echo_label"
typing_echo.textContent = "Awaiting pilot identification..."
typing_echo.style("color: #aaaaaa; font-style: italic; margin-bottom: 20px;")
ba(typing_echo)

def on_type(text):
    ge("echo_label").textContent = f"Live typing: {text}"
pilot_input.oninput = on_type

# Slider with Real-Time 'oninput' Event
throttle_label = ce("text")
throttle_label.id = "throttle_display"
throttle_label.textContent = "Engine Throttle: 0%"
throttle_label.style("font-size: 16px; font-weight: bold; margin-top: 10px;")
ba(throttle_label)

throttle_slider = ce("slider")
throttle_slider.id = "throttle"
# The slider scales 0-100 under the hood based on our ce() setup
def on_slide(val):
    # val comes in as a float from our parser, we multiply back for display
    ge("throttle_display").textContent = f"Engine Throttle: {int(val * 10)}%"
throttle_slider.oninput = on_slide
ba(throttle_slider)

# Nested Containers (Div) for layout grouping
action_panel = ce("div")
action_panel.style("background-color: #222; border-radius: 8px; padding: 15px; margin-top: 20px;")
ba(action_panel)

# Interactive Button with rich CSS pseudo-states inside the Div
submit_btn = ce("button")
submit_btn.textContent = "ENGAGE THRUSTERS"
submit_btn.style("""
    button { 
        background-color: #007acc; 
        color: white; 
        border-radius: 6px; 
        padding: 12px; 
        font-size: 16px; 
        font-weight: bold;
    }
    button:hover { background-color: #0099ff; }
    button:pressed { background-color: #005c99; }
""")
ba(submit_btn, action_panel) # Appended to action_panel, NOT the main window

# Scrolling Log Window (scroll_div) for dynamic output
log_title = ce("h1")
log_title.textContent = "System Logs:"
log_title.style("margin-top: 20px; font-size: 14px; color: #888;")
ba(log_title)

log_window = ce("scroll_div")
log_window.style("background-color: #0a0a0a; border: 1px solid #333; min-height: 150px;")
ba(log_window)

# Button Click Event (Gathering data via 'ge' and appending to scroll_div)
def handle_engage():
    # Grab values from the registry
    pilot = ge("pilot_name").value or "Unknown Pilot"
    throttle = ge("throttle").value * 10

    # Create a new dynamic log entry
    log_entry = ce("p")
    log_entry.textContent = f"> {pilot} engaged engines at {int(throttle)}%"
    log_entry.style("color: #00ff00; font-family: monospace; font-size: 13px; margin: 2px;")

    # Append the new text directly into the scrolling window
    ba(log_entry, log_window)

submit_btn.onclick = handle_engage

# Launch the App
run_app()

pyside6dom

A pure, web-style Document Object Model (DOM) interface for building PySide6 desktop applications natively in Python. Write desktop GUIs using the web syntax you already know.

Installation

pip install pyside6dom

🚀 Quickstart Example: Settings Panel

This example demonstrates global CSS styling, checkboxes, dropdowns, and real-time event handling using pure DOM syntax.

from pyside6dom import *

# Initialize Window
init_window("Settings Panel", 400, 500)

# Global Stylesheet (CSS)
set_theme("""
    div {
        background-color: #1e1e1e;
        color: #ffffff;
        font-family: Arial, sans-serif;
        font-size: 14px;
    }
    h1#title_heading {
        font-size: 22px;
        font-weight: bold;
        color: #00ffcc;
        margin-bottom: 10px;
    }
    button {
        background-color: #007acc;
        color: white;
        border-radius: 4px;
        padding: 10px;
        font-weight: bold;
        margin-top: 15px;
    }
    button:hover { background-color: #0099ff; }
    button:pressed { background-color: #005c99; }
    
    select {
        padding: 6px;
        background-color: #2b2b2b;
        border: 1px solid #555;
        border-radius: 3px;
    }
    select option {
        background-color: #2b2b2b;
        selection-background-color: #007acc;
        selection-color: white;
    }
    scroll_div {
        border: 1px solid #444;
        background-color: #111;
        margin-top: 10px;
    }
""")

# Build the UI
header = ce("h1")
header.id = "title_heading"
header.textContent = "⚙️ Settings Panel"
ba(header)

mode_label = ce("text")
mode_label.textContent = "Select Operating Mode:"
ba(mode_label)

mode_select = ce("select")
mode_select.id = "app_mode"
mode_select.options = ["Standard", "Advanced", "Developer"]
ba(mode_select)

debug_checkbox = ce("checkbox")
debug_checkbox.id = "debug_flag"
debug_checkbox.textContent = "Enable Debug Logging"
debug_checkbox.checked = True
ba(debug_checkbox)

apply_btn = ce("button")
apply_btn.textContent = "Apply Settings"
ba(apply_btn)

log_window = ce("scroll_div")
ba(log_window)

# Handle Events
def handle_apply():
    selected = ge("app_mode").value
    debug = ge("debug_flag").checked
    
    log = ce("p")
    log.textContent = f"> Mode: {selected} | Debug: {debug}"
    log.style("color: #00ff00; font-family: monospace;")
    ba(log, log_window)

apply_btn.onclick = handle_apply

# Launch
run_app()

Here is another example:

# pyside6dom_example.py

from pyside6dom import *

init_window("Settings Panel", 400, 500)

# ===
#  WORLDWIDE STYLESHEET (CSS)
# ===
set_theme("""
    div {
        background-color: #1e1e1e;
        color: #ffffff;
        font-family: Arial, sans-serif;
        font-size: 14px;
    }
    text {
        padding-top: 5px;
    }
    h1#title_heading {
        font-size: 22px;
        font-weight: bold;
        color: #00ffcc;
        margin-bottom: 10px;
    }
    button {
        background-color: #007acc;
        color: white;
        border-radius: 4px;
        padding: 10px;
        font-weight: bold;
        margin-top: 15px;
    }
    button:hover { background-color: #0099ff; }
    button:pressed { background-color: #005c99; }
    
    select {
        padding: 6px;
        background-color: #2b2b2b;
        border: 1px solid #555;
        border-radius: 3px;
    }
    /* This fixes the missing hover highlight in dropdowns! */
    select option {
        background-color: #2b2b2b;
        selection-background-color: #007acc;
        selection-color: white;
    }
    
    scroll_div {
        border: 1px solid #444;
        background-color: #111;
        margin-top: 10px;
    }
""")

# ===
#  UI BUILDER
# ===

header = ce("h1")
header.id = "title_heading"
header.textContent = "⚙️ Settings Panel"
ba(header)

mode_label = ce("text")
mode_label.textContent = "Select Operating Mode:"
ba(mode_label)

mode_select = ce("select")
mode_select.id = "app_mode"
mode_select.options = ["Standard", "Advanced", "Developer"]
ba(mode_select)

debug_checkbox = ce("checkbox")
debug_checkbox.id = "debug_flag"
debug_checkbox.textContent = "Enable Debug Logging"
debug_checkbox.checked = True
ba(debug_checkbox)

apply_btn = ce("button")
apply_btn.textContent = "Apply Settings"
ba(apply_btn)

log_window = ce("scroll_div")
ba(log_window)

def handle_apply():
    selected = ge("app_mode").value
    debug = ge("debug_flag").checked
    
    log = ce("p")
    log.textContent = f"> Mode: {selected} | Debug: {debug}"
    log.style("color: #00ff00; font-family: monospace;") # Inline overrides still work!
    ba(log, log_window)

apply_btn.onclick = handle_apply

run_app()

Easy Example:

# pyside6dom_easy_example.py

from pyside6dom import *

init_window("Our App", 600, 400)

welcomeMessage = ce('text')
welcomeMessage.textContent = 'Welcome'
ba(welcomeMessage)

sayHiBtn = ce('button')
sayHiBtn.textContent = 'Hi'
def handle_click():
    welcomeMessage.textContent = 'Hi'
sayHiBtn.onclick = handle_click
ba(sayHiBtn)

sayHowdyBtn = ce('button')
sayHowdyBtn.textContent = 'Howdy'
def handle_click():
    welcomeMessage.textContent = 'Howdy'
sayHowdyBtn.onclick = handle_click
ba(sayHowdyBtn)

sayThisBtn = ce('button')
sayThisBtn.textContent = 'This'
def handle_click(message):
    welcomeMessage.textContent = message
sayThisBtn.onclick = lambda: handle_click('Hey Now')
ba(sayThisBtn)

run_app()

Scrollable Div Example:

# pyside6dom_scroll_box_example.py

from pyside6dom import *

init_window("Our App", 600, 400)

welcomeMessage = ce('text')
welcomeMessage.textContent = 'Welcome'
welcomeMessage.style("font-size: 30px; font-weight: bold;")
ba(welcomeMessage)

# Create a specific scrollable container for the buttons
messageBtns_scroll_box = ce('scroll_div')
messageBtns_scroll_box.style("border: 2px solid #555; background-color: #1a1a1a; min-height: 200px;")
ba(messageBtns_scroll_box)

# Create buttons and append them TO the scroll box
sayHiBtn = ce('button')
sayHiBtn.textContent = 'Hi'
def handle_click_hi():
    welcomeMessage.textContent = 'Hi'
sayHiBtn.onclick = handle_click_hi
ba(sayHiBtn, messageBtns_scroll_box) # Notice the second argument

sayHowdyBtn = ce('button')
sayHowdyBtn.textContent = 'Howdy'
def handle_click_howdy():
    welcomeMessage.textContent = 'Howdy'
sayHowdyBtn.onclick = handle_click_howdy
ba(sayHowdyBtn, messageBtns_scroll_box)

sayThisBtn = ce('button')
sayThisBtn.textContent = 'This'
def handle_click_message(message):
    welcomeMessage.textContent = message
sayThisBtn.onclick = lambda: handle_click_message('Hey Now')
ba(sayThisBtn, messageBtns_scroll_box)

run_app()

MORE EXAMPLES:

# pyside6dom_example.py

from pyside6dom import *

init_window("Our App", 600, 400)

number_input = ce('input')
number_input.placeholder = 'Enter number'
ba(number_input)

enter_btn = ce('button')
enter_btn.textContent = 'Enter'
def handle_click():
    print(number_input.value)
    ge('result_label').textContent = number_input.value
enter_btn.onclick = handle_click
ba(enter_btn)

result_label = ce('text')
result_label.id = 'result_label'
result_label.textContent = 'Result'
result_label.style("font-size: 30px; font-weight: bold")
ba(result_label)

run_app()

# pyside6dom_example.py

from pyside6dom import *

init_window("Area of Square Calculator", 600, 400)

area_label = ce('text')
area_label.textContent = 'Area of a Square Calculator'
area_label.style("font-size: 40px; font-weight: bold; color: rgb(0, 255, 255);")
ba(area_label)

side_input = ce('input')
side_input.placeholder = 'Enter a Side Length'
ba(side_input)

enter_btn = ce('button')
enter_btn.textContent = 'Enter'
def handle_click():
    side = float(side_input.value)
    area = side * side
    ge('result_label').textContent = area
enter_btn.onclick = handle_click
ba(enter_btn)

result_label = ce('text')
result_label.id = 'result_label'
result_label.textContent = 'Result'
result_label.style("font-size: 40px; font-weight: bold")
ba(result_label)

run_app()

# pyside6dom_example.py

from pyside6dom import *

init_window("Area of a Square Calculator", 600, 450)

area_label = ce('h1')
area_label.textContent = 'Area of a Square'
area_label.style("font-size: 32px; font-weight: bold; color: rgb(0, 255, 255); margin-bottom: 10px;")
ba(area_label)

side_input = ce('input')
side_input.placeholder = 'Enter a Side Length...'
ba(side_input)

enter_btn = ce('button')
enter_btn.textContent = 'Calculate Area'
def handle_click():
    # Grab and calculate
    side = float(side_input.value)
    area = side * side

    # Create a brand new element for this specific calculation
    history_entry = ce('p')
    history_entry.textContent = f"Side: {side}  →  Area: {area}"
    history_entry.style("font-size: 18px; color: rgb(0, 255, 255); font-family: Arial; border-bottom: 1px dashed rgb(255, 255, 255); padding-bottom: 5px;")

    # Append the new element directly into the scroll box
    ba(history_entry, result_scroll_box)

    # Clear the input box so it is ready for the next number
    side_input.value = ""

enter_btn.onclick = handle_click
ba(enter_btn)

# The container that will hold our history
result_scroll_box = ce('scroll_div')
result_scroll_box.style("min-height: 50px; border: 1px solid rgb(255, 255, 255); background-color: rgb(0, 0, 0); margin-top: 10px; padding: 5px;")
ba(result_scroll_box)

run_app()

# pyside6dom_example.py

from pyside6dom import *

init_window("Area of a Rectangle Calculator", 600, 450)

area_label = ce('h1')
area_label.textContent = 'Area of a Rectangle'
area_label.style("font-size: 32px; font-weight: bold; color: rgb(0, 255, 255); margin-bottom: 10px;")
ba(area_label)

length_input = ce('input')
length_input.placeholder = 'Enter Length...'
ba(length_input)

width_input = ce('input')
width_input.placeholder = 'Enter Width...'
ba(width_input)

enter_btn = ce('button')
enter_btn.textContent = 'Calculate Area'
def handle_click():
    # Grab and calculate
    length = float(length_input.value)
    width = float(width_input.value)
    area = length * width

    # Create a brand new element for this specific calculation
    history_entry = ce('p')
    history_entry.textContent = f"Length: {length}  |  Width: {width}  →  Area: {area}"
    history_entry.style("font-size: 18px; color: rgb(0, 255, 255); font-family: Arial; border-bottom: 1px dashed rgb(255, 255, 255); padding-bottom: 5px;")

    # Append the new element directly into the scroll box
    ba(history_entry, result_scroll_box)

    # Clear both input boxes so they are ready for the next numbers
    length_input.value = ""
    width_input.value = ""

enter_btn.onclick = handle_click
ba(enter_btn)

# The container that will hold our history
result_scroll_box = ce('scroll_div')
result_scroll_box.style("min-height: 50px; border: 1px solid rgb(255, 255, 255); background-color: rgb(0, 0, 0); margin-top: 10px; padding: 5px;")
ba(result_scroll_box)

run_app()

Updating Clock

# pyside6dom_setInterval_clock.py

from pyside6dom import *
from datetime import datetime

init_window("Digital Clock", 400, 200)

clock_label = ce('h1')
clock_label.style("font-size: 60px; font-weight: bold; color: rgb(0, 255, 255); qproperty-alignment: AlignCenter; margin-top: 20px;")
ba(clock_label)

date_label = ce('text')
date_label.style("font-size: 24px; color: rgb(255, 255, 255); qproperty-alignment: AlignCenter;")
ba(date_label)

def update_clock():
    now = datetime.now()
    clock_label.textContent = now.strftime("%I:%M:%S %p")
    date_label.textContent = now.strftime("%B %d, %Y")

update_clock()

# Just like JavaScript
setInterval(update_clock, 1000)

run_app()

textarea for Notes

# pyside6dom_example.py

from pyside6dom import *

init_window("Notepad App", 500, 400)

theTitle = ce('h1')
theTitle.textContent = "Notes"
theTitle.style("color: rgb(0, 255, 255); margin-bottom: 10px;")
ba(theTitle)

# The new textarea tag
note_pad = ce('textarea')
note_pad.placeholder = "Start typing your notes here...\n(Press Enter for a new line)"
note_pad.style("background-color: rgb(26, 26, 26); color: rgb(0, 255, 255); font-family: Arial; font-size: 24px;")
ba(note_pad)

char_count = ce('text')
char_count.textContent = "Characters: 0"
char_count.style("color: rgb(130, 130, 130); text-align: right;")
ba(char_count)

# Real-time event mapping
def update_count(text):
    char_count.textContent = f"Characters: {len(text)}"

note_pad.oninput = update_count

run_app()

# pyside6dom_open_url.py

import webbrowser

from pyside6dom import *

set_theme("""
    body {
        background-color: rgb(30, 30, 30);
    }
    button {
        background-color: rgb(0, 0, 0);
        color: cyan;
        /* we write 1px before solid */
        border: 1px solid rgb(255, 255, 255);
        border-radius: 5px;
    }
    button:hover {
        background-color: #555;
        border-color: rgb(0, 255, 255);
    }
    input {
        border: 1px solid white;
    }
""")

####

def goTo_url(url):
    if url.startswith('http://') or url.startswith('https://'):
        try:
            webbrowser.open(url)
            print("Web page opened successfully.")
            print(url)
        except Exception as e:
            print("An error occurred:", e)
    else:
        print("Enter a URL starting with 'http://' or 'https://'")

####

init_window('Website Links', 700, 500)

theTitle = ce('text')
theTitle.textContent = 'Websites'
ba(theTitle)

web_btns_scroll_box = ce('scroll_div')
web_btns_scroll_box.style('border: 1px solid white;')
ba(web_btns_scroll_box)

google_btn = ce('button')
google_btn.textContent = 'Google'
google_btn.onclick = lambda: goTo_url('https://www.google.com')
ba(google_btn, web_btns_scroll_box)

vidmax_btn = ce('button')
vidmax_btn.textContent = 'Vid Max'
vidmax_btn.onclick = lambda: goTo_url('https://vidmax.com/')
ba(vidmax_btn, web_btns_scroll_box)

rumble_btn = ce('button')
rumble_btn.textContent = 'Rumble'
rumble_btn.onclick = lambda: goTo_url('https://rumble.com/')
ba(rumble_btn, web_btns_scroll_box)

kick_btn = ce('button')
kick_btn.textContent = 'Kick'
kick_btn.onclick = lambda: goTo_url('https://kick.com/')
ba(kick_btn, web_btns_scroll_box)

youtube_btn = ce('button')
youtube_btn.textContent = 'YouTube'
youtube_btn.onclick = lambda: goTo_url('https://youtube.com/')
ba(youtube_btn, web_btns_scroll_box)

run_app()

Stopwatch

# pyside6dom_stopwatch.py

from pyside6dom import *

# worldwide CSS style

set_theme("""
    body {
        background-color: #1a1a1a;
    }
    text {
        color: rgb(0, 255, 255);
        qproperty-alignment: AlignCenter;
    }
    button {
        background-color: #333333;
        color: rgb(255, 255, 255);
        border: 1px solid rgb(0, 255, 255);
        border-radius: 5px;
        padding: 8px;
        font-size: 18px;
        font-weight: bold;
        margin-top: 10px;
    }
    button:hover {
        background-color: rgb(0, 255, 255);
        color: rgb(0, 0, 0);
    }
""")

####

def start_clock():
    global timer_id, is_running
    # Only start if it isn't already running, to prevent runaway timers
    if not is_running:
        timer_id = setInterval(tick, 100) # Run every 100 milliseconds
        is_running = True

def format_time(t):
    minutes = t // 600
    seconds = (t // 10) % 60
    tenths = t % 10
    # The :02d forces numbers to have a leading zero (e.g., 05 instead of 5)
    return f"{minutes:02d}:{seconds:02d}:{tenths}"

def tick():
    global tenths_of_second
    tenths_of_second += 1
    time_display.textContent = format_time(tenths_of_second)

def stop_clock():
    global timer_id, is_running
    if is_running:
        clearInterval(timer_id)
        is_running = False

def reset_clock():
    global tenths_of_second
    stop_clock() # Stop the timer first
    tenths_of_second = 0 # Reset the math
    time_display.textContent = "00:00:0" # Reset the screen

####

init_window("Stopwatch", 350, 450)

# The User Interface
theTitle = ce('text')
theTitle.textContent = "Stopwatch"
theTitle.style("font-size: 28px; font-weight: bold; margin-top: 10px;")
ba(theTitle)

time_display = ce('text')
time_display.textContent = "00:00:0"
time_display.style("font-size: 55px; font-family: monospace; margin-top: 20px; margin-bottom: 20px;")
ba(time_display)

start_btn = ce('button')
start_btn.textContent = "Start"
start_btn.onclick = start_clock
ba(start_btn)

stop_btn = ce('button')
stop_btn.textContent = "Stop"
stop_btn.onclick = stop_clock
ba(stop_btn)

reset_btn = ce('button')
reset_btn.textContent = "Reset"
reset_btn.onclick = reset_clock
ba(reset_btn)

# The Application Logic
tenths_of_second = 0
timer_id = None
is_running = False

run_app()

List of Dictionaries

# list_of_dictionaries_show_all.py

from pyside6dom import *

people = [
    {
        "name": "Jane",
        "score": 93
    },

    {
        "name": "Joan",
        "score": 90
    },

    {
        "name": "Melissa",
        "score": 98
    },

    {
        "name": "Jennifer",
        "score": 91
    },

    {
        "name": "Tabitha",
        "score": 88
    },

    {
        "name": "Sabrina",
        "score": 85
    },

    {
        "name": "Nicole",
        "score": 94
    },

    {
        "name": "Britney",
        "score": 92
    },

    {
        "name": "Zoe",
        "score": 82
    },

    {
        "name": "Clarissa",
        "score": 79
    },

    {
        "name": "Bonnie",
        "score": 100
    },
]

init_window('Scores', 700, 500)

people_scroll_box = ce('scroll_div')
people_scroll_box.id = 'people_scroll_box'
people_scroll_box.style("border: 1px solid rgb(255, 255, 255);")
ba(people_scroll_box)

for person in people:
    name = ce('button')
    name.textContent = f"{person['name']}: {person['score']}"
    name.style("font-size: 30px; font-weight: bold; font-color: aqua;")
    # we can type font-color or color, either is fine
    
    # Freeze the current person into a local variable 'p'
    def handle_click(p=person):
        print(f"{p['name']}: {p['score']}")
        
    name.onclick = handle_click
    ba(name, people_scroll_box)

####

run_app()

List of Dictionaries Show All

# list_of_dictionaries_show_all.py

from pyside6dom import *

people = [
    {
        "name": "Jane",
        "score": 93
    },

    {
        "name": "Joan",
        "score": 90
    },

    {
        "name": "Melissa",
        "score": 98
    },

    {
        "name": "Jennifer",
        "score": 91
    },

    {
        "name": "Tabitha",
        "score": 88
    },

    {
        "name": "Sabrina",
        "score": 85
    },

    {
        "name": "Nicole",
        "score": 94
    },

    {
        "name": "Britney",
        "score": 92
    },

    {
        "name": "Zoe",
        "score": 82
    },

    {
        "name": "Clarissa",
        "score": 79
    },

    {
        "name": "Bonnie",
        "score": 100
    },
]

init_window('Scores', 700, 500)

output_label = ce('text')
output_label.style('font-size: 30px; font-weight: bold')
ba(output_label)

people_scroll_box = ce('scroll_div')
people_scroll_box.id = 'people_scroll_box'
people_scroll_box.style("border: 1px solid rgb(255, 255, 255);")
ba(people_scroll_box)

for person in people:
    name_btn = ce('button')
    name_btn.textContent = f"{person['name']}: {person['score']}"
    name_btn.style("font-size: 30px; font-weight: bold; color: aqua;")
    # we can type color or font-color, either is fine

    # Freeze the current person into a local variable 'p'
    def handle_click(p=person):
        print(f"{p['name']}: {p['score']}")
        output_label.textContent = f"{p['name']}: {p['score']}"
        
    name_btn.onclick = handle_click
    ba(name_btn, people_scroll_box)

####

run_app()

Dictionary of Dictionaries show all

# dictionary_of_dictionaries_show_all.py

from pyside6dom import *

people = {
    "jane_doe": {
        "first_name": "Jane",
        "last_name": "Doe",
        "score": 93
    },
    "joan_smith": {
        "first_name": "Joan",
        "last_name": "Smith",
        "score": 90
    },
    "melissa_taylor": {
        "first_name": "Melissa",
        "last_name": "Taylor",
        "score": 98
    },
    "jennifer_parker": {
        "first_name": "Jennifer",
        "last_name": "Parker",
        "score": 91
    },
    "tabitha_brooks": {
        "first_name": "Tabitha",
        "last_name": "Brooks",
        "score": 88
    },
    "sabrina_clark": {
        "first_name": "Sabrina",
        "last_name": "Clark",
        "score": 85
    },
    "nicole_morgan": {
        "first_name": "Nicole",
        "last_name": "Morgan",
        "score": 94
    },
    "britney_cooper": {
        "first_name": "Britney",
        "last_name": "Cooper",
        "score": 92
    },
    "zoe_baker": {
        "first_name": "Zoe",
        "last_name": "Baker",
        "score": 82
    },
    "clarissa_hayes": {
        "first_name": "Clarissa",
        "last_name": "Hayes",
        "score": 79
    },
    "bonnie_bell": {
        "first_name": "Bonnie",
        "last_name": "Bell",
        "score": 100
    }
}

init_window('Scores', 700, 600)

output_label = ce('text')
ba(output_label)

people_scroll_box = ce('scroll_div')
people_scroll_box.id = 'people_scroll_box'
people_scroll_box.style("border: 1px solid rgb(255, 255, 255);")
ba(people_scroll_box)

for person_key, person_data in people.items():
    name_btn = ce('button')
    # Display the properly capitalized first and last name on the button
    name_btn.textContent = f"{person_data['first_name']} {person_data['last_name']}: {person_data['score']}"
    name_btn.style("font-size: 25px; font-weight: bold; color: aqua;")

    # Freeze the lowercase key AND the inner dictionary data
    def handle_click(p_key=person_key, p_data=person_data):
        # Print the lowercase key first to prove we are pulling it from the top level
        print(f"Dictionary Key: '{p_key}' -> Student: {p_data['first_name']} {p_data['last_name']}, Score: {p_data['score']}")

        output_label.textContent = f"Dictionary Key: '{p_key}' -> Student: {p_data['first_name']} {p_data['last_name']}, Score: {p_data['score']}"

    name_btn.onclick = handle_click
    ba(name_btn, people_scroll_box)

####

run_app()

Class

from pyside6dom import *

set_theme("""
text {
    font-size: 40px;
    font-weight: bold;
}
""")

####

class Dog:
    def __init__(this, name, weight):
        this.name = name
        this.weight = weight

####

fido = Dog("Fido", 16)
rex = Dog("Rex", 20)

####

init_window('Dog Class', 700, 500)

dog_label = ce('text')
dog_label.textContent = fido.name + ' weighs ' + str(fido.weight) + ' lbs'
ba(dog_label)

# our shortcut cl
# we could alternatively write console.log or
# we could write print instead
cl(fido.name + ' weighs ' + str(fido.weight) + ' lbs')

run_app()

####

'''
Fido weighs 16 lbs
'''

Pandas

Read CSV Show with innerHTML

# read_csv_show_with_innerHTML.py

import pandas as pd
from pyside6dom import *

theData = pd.read_csv('data.csv')

init_window('Read CSV File', 700, 400)

output = ce('text')
# Inject the Pandas HTML directly into the text element
output.innerHTML = theData.to_html(index=False, border=1)

ba(output)

run_app()

https://github.com/ChristopherAndrewTopalian/pyside6dom

How to Download the GitHub Repository

  1. Click the green Code Button on the GitHub page
  2. Choose Download ZIP
  3. Save the Zip File
  4. Extract All

Hapy Scripting :-)


//----//

// Dedicated to God the Father

// Copyright (c) 2026-present Christopher Andrew Topalian

// Apache License Version 2.0, January 2004 http://www.apache.org/licenses/

// GitHub: https://github.com/ChristopherAndrewTopalian/pyside6dom

// PyPI: https://pypi.org/project/pyside6dom/

// https://github.com/ChristopherAndrewTopalian

// https://github.com/ChristopherTopalian

// https://sites.google.com/view/CollegeOfScripting

Release files for pyside6dom 0.3.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyside6dom 0.3.8
File Size Uploaded
pyside6dom-0.3.8.tar.gz 34.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyside6dom 0.3.8
File Interpreter ABI Platform
pyside6dom-0.3.8-py3-none-any.whl Python 3 none any Details

Total release size: 53.0 kB

Release files / pyside6dom-0.3.8.tar.gz

Download URL pyside6dom-0.3.8.tar.gz
Size 34.4 kB
Tags Source
SHA-256 checksum
How to use checksums
6f7928fab78cd65a6fae814a36e817ba29ad2ffcfb1742148b72c4d39f1669a0
BLAKE2b-256 checksum
How to use checksums
7b0775c21dc42e542446057286d4a1b92d0199801929194535d0437ec17efbd8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.0

Release files / pyside6dom-0.3.8-py3-none-any.whl

Download URL pyside6dom-0.3.8-py3-none-any.whl
Size 18.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5547f3470fb1d54683669af8b931801601bbcad1fbe02fe6a084040dca3f8ef2
BLAKE2b-256 checksum
How to use checksums
456586dbbe41902b353686c7a139928284fcba542724b75a930aecc1a6ef0d30
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.0

Release history Release notifications | RSS feed

0.4.8

2 release files

0.4.7

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.9

2 release files

This release

0.3.8 This release

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page