Vanilla Frontend
Use TauPy with plain HTML, CSS, and JavaScript-no React or Python widgets. The vanilla template serves dist/ as-is while TauPy provides the window, WebSocket bridge, and backend events.
1. When to pick Vanilla
- You already have static HTML/CSS or a lightweight JS app and need a desktop wrapper.
- You want zero React/NPM dependencies (or will add your own bundler later).
- You prefer to keep backend logic in Python but author UI in raw markup.
2. Scaffold a project
Template contents:
- main.py - TauPy backend in AppMode.RAW_HTML.
- dist/ - index.html, style.css, main.js, plus client.js (WebSocket bridge).
- launcher/ - taupy.exe + WebView2Loader.dll.
- taupy.toml - ports and build flags.
Layout:
my_app/
main.py
dist/
index.html
style.css
main.js
client.js
launcher/
taupy.exe
WebView2Loader.dll
taupy.toml
Tip: Replace
dist/with assets from any bundler; keepclient.jsor reimplement its bridge.
3. Development workflow
- Run
taupy dev. Vanilla mode watchesdist/and triggers a live reload on save. - Default ports: HTTP
8000, WebSocket8765. Override withTAUPY_HTTP_PORTandTAUPY_WS_PORT. TAUPY_EXTERNAL_HTTPis not needed; assets are served locally.- Add
--open-devtools(orTAUPY_OPEN_DEVTOOLS=1) to debug in the TauPy window.
4. Wire events from HTML to Python
Attach data-component-id to elements. client.js sends clicks and inputs over WebSocket.
HTML (dist/index.html):
<button data-component-id="save-btn">Save</button>
<input type="text" data-component-id="search-box" />
<script src="./client.js"></script>
<script type="module" src="./main.js"></script>
Python (main.py):
import asyncio
from taupy import App, AppMode
from taupy.events import Click, Input
app = App("Vanilla TauPy", 900, 640, mode=AppMode.RAW_HTML)
@app.dispatcher.on_click("save-btn")
async def save(_: Click):
print("Save requested")
@app.dispatcher.on_input("search-box")
async def on_search(evt: Input):
print("Query:", evt.value)
async def main():
await app.run()
if __name__ == "__main__":
asyncio.run(main())
client.js already handles DOM updates (update_text, update_html, replace, update_input), theme changes, and hot_reload messages from Python.
5. Custom messages and window commands
You can send custom payloads over the same WebSocket:
// dist/main.js
const socket = new WebSocket("ws://localhost:8765");
socket.addEventListener("open", () => {
socket.send(JSON.stringify({ type: "window_cmd", command: { type: "toggle_fullscreen" } }));
});
Supported window commands include toggle_fullscreen, minimize, maximize, restore, set_title, set_size, and more (see App.send_window_command).
6. Build and distribute
The build copies dist/, bundles the backend with Nuitka, and writes target/ with app.exe, dist/, and launcher/. See Build & Distribution for release details.
7. Tips
- Keep
data-component-idunique to avoid handler conflicts. - If antivirus flags onefile builds, set
onefile = falseintaupy.tomland rebuild. - To debug WebSocket traffic, open DevTools and watch console logs; verify ports
8000/8765are free.