ViewForge is a minimalist Python UI framework for building desktop apps with web technologies and live reload support.
Project description
ViewForge
ViewForge is a modern Python desktop UI framework that renders HTML and web components inside a pywebview window.
It supports component-based rendering, declarative event registration, reactive state with signals, and flexible routing — all in Python.
✨ Features
- ✅ Component-based architecture (Text, Button, Stack, etc.)
- 🔗 Declarative event binding via
@handler() - 🧠 Central Python event router for dynamic dispatch
- 🧩 Flexible styling via CSS-style dicts
- 🌐 Built-in router with support for path params and query strings
- ⚡ Hot reload with
Ctrl+R - 🔁 Signals for reactive state
- 📦 Modular, extensible, no build step required
📁 Project Structure
viewforge/
├── core/ # App, Component, Registry
├── ui/ # elements/, layout/, links/
├── routing/ # route decorators, RouterView
├── state/ # Signal, Store
├── rendering/ # DOM and HTML rendering logic
├── utils/ # CSS, JS utilities, case handling
├── adapters/ # Optional UI system adapters (Shoelace, BeerCSS)
├── plugins/ # Debug tools, hot reload
└── main.py # App entry point
🚀 Getting Started
1. Define a handler
from viewforge.core.registry import handler
@handler()
def handle_click():
print("Button clicked!")
2. Use the handler in a Button
from viewforge.ui.elements import Button
Button("Click Me", on_click=handle_click)
3. Launch the app
from viewforge.core import App
App().run(lambda: [Button("Hi")])
🧠 How Events Work
-
You define Python handlers with
@handler()→ they get a unique name likeon_handle_click -
Components like
Buttonrender HTML like:<sl-button onclick="vf('on_handle_click')">Click</sl-button>
-
The global
vf(...)JS function relays to Python viapywebview.api.handle_event(...) -
The Python router calls your function:
def handle_event(self, name, *args): return handler_registry.get()[name](*args)
🌐 Routing Example
from viewforge.routing import route
@route("/user/<id>", "User Profile")
def user_profile(params, route):
return Text(f"Viewing user {params['id']}")
💡 Signals
from viewforge.state import Signal
count = Signal(0)
Button("Increment", on_click=lambda: count.set(count.get() + 1))
Text(lambda: f"Count: {count.get()}")
🔧 Advanced Tips
- All components support
style={}for CSS properties - You can nest layout containers like
Stack,Box, or build your own - Router supports dynamic segments and query strings
📦 Coming Soon
- ✅ FormGroup with validation
- 🧭 View decorators for route views
- 🌈 Light/dark theme switching
🧼 Philosophy
ViewForge is minimal by design — no JavaScript build steps, no virtual DOM diffing — just clean Python and direct HTML rendering.
Build UIs in Python. Render like the web.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file viewforge-0.1.0.dev2.tar.gz.
File metadata
- Download URL: viewforge-0.1.0.dev2.tar.gz
- Upload date:
- Size: 30.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0aa2078d892ef0cd1f437d34f6b9f1b94b148e09593d0b4d1cfc4389efa6ee0
|
|
| MD5 |
635bc922f14f9f89e881200125114000
|
|
| BLAKE2b-256 |
66af77dccee88228b1ddc9000e074f643c0327bc0582e0ac3363881f32bfbb59
|
File details
Details for the file viewforge-0.1.0.dev2-py3-none-any.whl.
File metadata
- Download URL: viewforge-0.1.0.dev2-py3-none-any.whl
- Upload date:
- Size: 36.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58c385cde19309e67f5440b157f12f498cdc950e3c6dcd1b73ba1d7b14337524
|
|
| MD5 |
bc704e2268226c0a887b7fd90c60f891
|
|
| BLAKE2b-256 |
2af03bef4cc11fedf551cad59dc53c6c7350404ad8bd8e985114941f3071d573
|