Keep Tkinter — embed a real system WebView in your Frame (wry, child-window embedding)
Project description
tkwry
Keep Tkinter — give it the WebView it never had.
Embed a real system WebView (wry) inside your Frame: modern HTML, JS, and IPC in the same layout as your buttons and tabs — one mainloop, no floating overlay.
Alpha — Early preview (see PyPI badge for the current version). APIs and behavior may change without notice. Not recommended for production use yet.
📖 Overview
Tkinter is still a solid GUI shell — it just had no first-class way to host modern web content inside a widget. Overlay-style WebViews drift out of sync when you move, resize, or switch tabs.
tkwry fills that missing piece:
- True child embedding —
build_as_childvia HWND, NSView, or X11 window ID - One event loop — Tk
mainlooponly; no separate app runtime - IPC bridge — JavaScript → Python callbacks without freezing the UI
- Layout-aware — tracks
pack/grid/place, tabs, andPanedWindow
Pre-built abi3 wheels ship for Windows (x86_64) and macOS (Apple Silicon + Intel). Linux is supported via source install (sdist / git) — PyPI wheels for Linux are intentionally not published.
🔧 Requirements
- Python 3.10+
- Tkinter (included with most Python builds)
- Windows (x86_64 only)
- WebView2 Runtime must be installed (pre-installed on many Windows 10/11 systems).
- Without WebView2, tkwry is not supported on Windows — there is no fallback engine.
- macOS — 11 (Big Sur) or later; Apple Silicon (arm64) or Intel (x86_64); system WKWebView (no extra runtime)
- Linux — WebKitGTK 4.1 + GTK 3 dev packages; X11 or XWayland (
$DISPLAY); build the extension from source (see below)
📦 Installation
Install from PyPI (Windows / macOS wheels):
pip install tkwry
Developing or running examples from a git clone — use an editable install so Python picks up this repo (not an older copy in site-packages):
pip install -e .
Or install from GitHub for the latest changes:
pip install git+https://github.com/mashu3/tkwry.git
Linux (source install)
Linux is fully supported, but only as a source build — not via a PyPI wheel. Install system dependencies, then:
# Debian / Ubuntu
sudo apt install \
libwebkit2gtk-4.1-dev \
libgtk-3-dev \
libglib2.0-dev
# Runtime (for end users of your app)
# sudo apt install libwebkit2gtk-4.1-0 libgtk-3-0
pip install maturin
git clone https://github.com/mashu3/tkwry.git
cd tkwry
pip install .
GTK events are pumped automatically on a Tk timer while your app runs.
🚀 Usage
Basic WebView
import tkinter as tk
from tkwry import WebView
root = tk.Tk()
root.geometry("900x600")
frame = tk.Frame(root, bg="#222")
frame.pack(fill="both", expand=True, padx=8, pady=8)
web = WebView(frame, url="https://github.com")
root.mainloop()
IPC (JavaScript → Python)
def on_message(msg: str) -> None:
print("from JS:", msg)
web = WebView(
frame,
html='<button onclick="window.ipc.postMessage(\'hi\')">send</button>',
ipc_handler=on_message,
)
Load HTML / evaluate JavaScript
web.load_html("<h1>Hello</h1>")
web.eval_js("document.title = 'Hi'")
web.eval_js_with_callback("document.title", print)
web.load_url("https://example.com")
web.reload()
print(web.url)
web.focus()
web.open_devtools()
Navigation / lifecycle callbacks
from tkwry import NewWindowResponse, PageLoadEvent
web = WebView(
frame,
url="https://example.com",
on_page_load=lambda evt, url: print(evt, url),
on_title_changed=lambda title: root.title(title),
on_navigation=lambda url: url.startswith("https://"),
on_new_window=lambda url: NewWindowResponse.Deny,
)
Drag & drop (native OS path)
File drops from Finder / Explorer are handled by the OS WebView. Your handler runs on the Tk main thread (tkwry queues events from WebKit automatically).
from tkwry import DragDropEvent
def on_drop(event, paths, position):
if event == DragDropEvent.Drop:
print("files:", paths)
web = WebView(frame, html="...", drag_drop_handler=on_drop)
See examples/dnd_demo.py.
Cleanup
web.destroy() # release native webview; host Frame is kept
# or destroy the host Frame — both tear down the webview
📚 API summary
| Category | Members |
|---|---|
| Content | load_url, load_html, reload, url |
| JavaScript | eval_js, eval_js_with_callback |
| IPC | set_ipc_handler |
| Callbacks | set_on_navigation, set_on_page_load, set_on_title_changed, set_on_new_window, set_drag_drop_handler |
| Appearance | set_background_color, focus, focus_parent, open_devtools, close_devtools, is_devtools_open |
| Layout | pack, grid, place (delegate to host Frame) |
| Lifecycle | destroy, destroyed, native |
Constructor options: url, html, ipc_handler, devtools, background_color,
user_agent, initialization_script, focused, plus the callback hooks above.
Enums: PageLoadEvent, NewWindowResponse, DragDropEvent.
⚠️ Known limitations
- Alpha — APIs may change; not recommended for production yet
- Windows — WebView2 Runtime required; systems without it are unsupported
- Linux — no pre-built PyPI wheel (source install only; this is intentional)
- DevTools — macOS uses private APIs; avoid in Mac App Store release builds
- macOS input — keyboard focus is shared between Tk and the WebView on the main thread; typing may feel slightly less snappy than a standalone browser (especially with IME on)
- Drag & drop — drop target is the WebView area only (not arbitrary Tk widgets; use tkinterdnd2 for those)
See CHANGELOG.md for release history.
🌐 Platform notes
| OS | Arch | Parent handle | Engine | Notes |
|---|---|---|---|---|
| Windows | x86_64 | Frame.winfo_id() → HWND |
WebView2 | WebView2 Runtime required |
| macOS | arm64, x86_64 | Toplevel content NSView |
WKWebView | See macOS embedding below |
| Linux | — | winfo_id() → X11 window ID |
WebKitGTK | GTK pumped on a Tk timer; source install |
macOS embedding
On macOS, Tk child Frames usually do not get their own NSView — that is a property of the Tk Aqua backend, not something tkwry can turn into per-frame native views without upstream Tk changes.
tkwry works around this by:
- Attaching the WebView to the toplevel content view
- Positioning it with
set_boundsto match yourFrame(<Configure>) - Hiding it with
set_visible(False)when the frame is unmapped (<Unmap>) — e.g. anotherttk.Notebooktab is selected
Keyboard focus (macOS): Rust routes clicks between Tk widgets and the WebView. You may notice slight input latency compared to a normal browser; v0.0.1 treats this as a known limitation.
You do not need extra code for tabs or panes — see examples/multi_demo.py. IPC, page-load, title, eval, and drag-and-drop handlers are dispatched on the Tk main thread via an internal queue (avoids WebKit deadlocks).
💡 Why child-window embedding?
Tkinter apps already have a window and a layout. The web belongs inside a Frame — same mainloop, same tabs and panes — not in a separate top-level webview that floats beside your UI. tkwry wraps wry's build_as_child against the native surface Tk gives your widgets.
🧩 Features
- Child-window embedding — WebView is a native child of your Tk window surface, not a floating overlay
- Bounds & visibility sync — follows
<Configure>,<Map>, and<Unmap>(tabs /Notebookwork out of the box on macOS) - Deferred callbacks — IPC, page load, title, eval results, and DnD queue to Tk (avoids macOS deadlocks)
- URL safety — normalizes and validates URLs before navigation
- DevTools —
open_devtools()/devtools=Truefor debugging - Native drag & drop — OS-level file drops into the WebView (no tkinterdnd2)
- Navigation hooks —
on_navigation,on_page_load,on_title_changed,on_new_window - Multiple layouts — works with
pack,grid,place,Notebook, andPanedWindow(see examples) - Plotly-ready — load HTML +
eval_jsfor interactive charts - Alpha, but tested — CI on Ubuntu (Xvfb + WebKitGTK), Windows, and macOS
📁 Examples
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
| Script | Description |
|---|---|
examples/url_demo.py |
URL bar + embedded page |
examples/ipc_demo.py |
JavaScript ↔ Tkinter IPC |
examples/multi_demo.py |
Multiple WebViews, tabs, panes |
examples/plotly_demo.py |
Plotly charts (pip install plotly) |
examples/dnd_demo.py |
Native file drag & drop into WebView |
python examples/url_demo.py
python examples/ipc_demo.py
python examples/multi_demo.py
python examples/plotly_demo.py
python examples/dnd_demo.py
📝 License
This project is licensed under the MIT License. See LICENSE.
This project links against wry, which is dual-licensed (Apache-2.0 or MIT). tkwry uses wry under MIT; see NOTICE for attribution.
👨💻 Author
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
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 tkwry-0.0.2.tar.gz.
File metadata
- Download URL: tkwry-0.0.2.tar.gz
- Upload date:
- Size: 59.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5fe3f07fdf8a266f273c560aed3f6071f9880a4c6f5dc978425ca077907483f
|
|
| MD5 |
5930f59bed84b217496a5856d996b967
|
|
| BLAKE2b-256 |
6b53c27948e8a41700c053afc1672566d87b23c0065f52d5bc84ac014abaec4e
|
File details
Details for the file tkwry-0.0.2-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: tkwry-0.0.2-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 337.8 kB
- Tags: CPython 3.10+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
209260edbf7bd6c0b8a750dd81efb4ec59a4d7fe1bf5602ac7ceee298dd47b93
|
|
| MD5 |
a018e8562733b9a6e209e2669e6c9329
|
|
| BLAKE2b-256 |
48b992783c021be80c53ef80e7487c8675d6df82d13bd3318962c3cfb4dba544
|
File details
Details for the file tkwry-0.0.2-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: tkwry-0.0.2-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 377.3 kB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5b33296eccb8c2a91c5ad7a921210a608578302831b54bbdc8b857fd3ecd9db
|
|
| MD5 |
39ecb847a3968df1bf19174bb6a727ad
|
|
| BLAKE2b-256 |
74dc25d215c9e17227430bebbfda3bfdd2b54614844d87bc1d373454bd041633
|
File details
Details for the file tkwry-0.0.2-cp310-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: tkwry-0.0.2-cp310-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 400.9 kB
- Tags: CPython 3.10+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a738c3f1f45d0156e25aaa285d52ca5ca844d07c0ccd2f15b98c8a4dc39789d
|
|
| MD5 |
3eb44b2d99b54fb2463b3e2f17931aa3
|
|
| BLAKE2b-256 |
013d33de4d546f6420ceb7e9620184dc5c68c6c1fd5a85e365a237bb07aca93a
|