Neony
Reactive desktop UI framework for Python, built on LumiView.
Overview
Status: alpha — the API is still settling. Feedback and contributions are welcome.
Neony renders a reactive DOM in a native window. You compose your UI from Python objects — components, layouts, styles — and Neony diff-updates the browser DOM automatically. No HTML, no JavaScript.
It builds on LumiView, which uses the same Rust
tao/wry webview stack as Tauri.
- Pure Python API — components, layouts and events, no need for non-python codes
- Fine-grained reactivity —
Signal/Computed/Effectprimitives with declarative bindings - Dirty-subtree diffing — only changed elements re-serialize; unchanged subtrees reuse cached snapshots
- Style direct-patch — pure style/attr changes (hover, focus, press) patch straight from the snapshot cache, skipping serialization and diff
- Same stack as Tauri — Rust
tao/wrywebviews via LumiView - 3 theme presets — dark / light / deep-blue via CSS custom properties
- (Optional) Frosted glass — translucent surfaces with backdrop blur
- Colour-matched glow — focus rings and hover glows tinted with each element's semantic colour
- Scroll indicator — native scrollbars are hidden; scroll surfaces get a theme-matched floating thumb (faint at rest, strengthens on scroll/hover, draggable, click-to-page) plus a dynamic edge fade that only shows where content actually overflows
- Custom window chrome — frameless, transparent, custom TitleBar
- (Supported platform only) Native window effects — blur / acrylic / mica materials
Installation
pip install neony
Requires Python 3.11+ and the platform WebView stack (WebKitGTK on Linux,
WebView2 on Windows, WKWebView on macOS). X11 is not supported — see the
Roadmap. The system tray needs
libayatana-appindicator on Linux.
Quick Start
from neony.application import Page, launch
from neony.application.elements import Button, Heading, Text, VStack
counter = Button("Click me")
async def on_click(event) -> None:
counter.label = "Clicked!"
counter.on_click(on_click)
page = Page(gap="16px").add(
VStack(
Heading("Hello, Neony", level=1),
Text("Build desktop UI in pure Python.", role="secondary"),
counter,
gap="12px",
)
)
launch(page, title="My App", width=480, height=360, devtools=True)
Components
Import from neony.application.elements.
| Component | Description |
|---|---|
Button |
Themed push button — primary / ghost / danger variants, hover & press feedback |
Checkbox |
Custom-styled checkbox with label and change event |
Radio / RadioGroup |
Mutual-exclusion radio options with group change carrying the value |
Switch |
Track + thumb toggle built on a native checkbox |
Select |
Themed dropdown — str or (value, label) options |
ComboBox |
Editable text with a themed suggestion popup |
Slider |
Slider with animated accent fill — stepped or stepless (step="any") |
Progress |
Progress bar with animated fill — determinate or sliding indeterminate |
Dialog |
Fixed scrim + centered glass panel — scrim / Escape / ✕ / click-away close |
Tooltip |
Hover bubble wrapped around an anchor, placement offsets, hover delay |
Dropdown |
Themed popup under a trigger — full keyboard nav + click-away close |
Menu |
Fixed popup positioned at the cursor (open_at(x, y) from contextmenu) |
Input |
Single-line text field — text / password / email / number… |
Heading |
Themed heading (h1–h6) with automatic sizing |
Text |
Inline body copy with semantic roles (primary / secondary / danger / success) |
Tabs |
Tab bar + panels, exactly one visible at a time — constructor children, selected_panel / selected_title / selected_key |
Accordion / Collapsible |
Expandable sections in one scroll flow — fluent .section(), multiple open mode, expanded_keys, on_change |
Tree / TreeNode |
Collapsible navigation tree + content host — arbitrary depth, fluent builders, leaf selection shows its panel on the right |
Icon |
One icon — Icon.image(url) fixed-size square or Icon.glyph(text), shared by TitleBar / Sidebar / Tabs / Tree |
Flex |
Generic flex container with full control |
VStack / HStack |
Vertical / horizontal flex stacks |
Spacer |
Flexible empty space that absorbs leftover room |
Separator |
Subtle horizontal divider |
GlassPanel |
Frosted-glass container with optional background image |
TitleBar |
Custom window chrome for frameless windows — drag, minimize / maximize / close |
Sidebar / SidebarItem |
Vertical navigation owning its content panes — Pane, SidebarGroup sections, per-pane shortcuts; glass-matched to the TitleBar |
Pane |
Selectable Sidebar entry + content panel — key, icon, section, shortcut |
SidebarGroup |
Titled section of a Sidebar — small uppercase label above its items |
Image |
Themed image in a rounded, overflow-hidden frame (src is any URL) |
Avatar |
User avatar — image, letter initial, or placeholder, optional corner badge |
Badge |
Status pill or corner count — variants, status dot, 99+ clamp, zero hides |
Card |
Titled content panel — actions, footer, optional frosted-glass glass surface |
All components share a fluent, chainable API — see the API reference for usage.
Window Features
- Frameless custom titlebar — set
decorations=False, add aTitleBar, and drag / minimize / maximize / close all work automatically. Seedocs/api.en.mdand thedemo_custom_window.pydemo. - Transparent windows & native effects —
transparent=Trueplusapply_blur(),apply_acrylic(),apply_mica(). Seedemo_transparent_panel.py. - Programmatic window control —
set_title(),set_size(),minimize(),toggle_maximize(),close(), … all onNeonApplication, withwindow_index=0for multi-window apps. - Multi-window —
run(*pages)opens one window per page, all sharing one event loop andapp.state.launch([...])accepts a list. Seedemo_multi_window.py. - System tray —
app.tray = Tray(icon, tooltip, items=[...])adds a tray icon with a native context menu;close_to_tray=Truehides the app instead of quitting on close. Linux needslibayatana-appindicator. Seedemo_tray.py.
Theming
Three built-in presets — DARK (default), LIGHT, DEEP_BLUE — exposed as
CSS custom properties on :root, so a theme switch redraws the whole UI with
zero DOM diff. Scrollbars and interaction glows (focus rings, hover halos)
reference the same --color-* tokens, so they follow theme switches too.
See the API reference for switching and custom themes.
Demos
Run from the repository root:
| File | Shows |
|---|---|
demo_hello.py |
Minimal first app (same as the Quick Start example) |
demo_gallery.py |
Component gallery with docs & code samples, glass TitleBar |
demo_custom_window.py |
Frameless window: TitleBar + Sidebar chrome |
demo_transparent_panel.py |
Floating transparent panel with native blur |
demo_multi_window.py |
Two windows sharing one app state |
demo_reactive.py |
Signal-based API: declarative bindings instead of manual refresh |
demo_accordion.py |
Accordion: expandable grouped sections in one scroll flow |
demo_tree.py |
Tree: collapsible navigation tree + content host |
demo_tray.py |
System tray: native menu + close-to-tray pattern |
demo_builder.py |
Minimal app built with Page + components + launch() |
uv run demo_gallery.py
Roadmap
Planned work lives in ROADMAP.md — performance, events, lifecycle, components, animation, platform integration and verification.
Development
This project uses uv as the environment manager and runner.
uv sync --group dev # install dependencies (incl. dev tools)
npm ci # install JS dev dependencies (vitest, jsdom)
uv run demo_gallery.py # run a demo
uv run pytest -q # run the Python test suite
uv run ruff check . # lint
uv run ruff format --check . # format check
uv run pyrefly check # type check
npm test # run the JS test suite (vitest)
License
Apache-2.0 © HarcicYang
Release files for neony 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| neony-0.1.2.tar.gz | 211.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| neony-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 384.6 kB
Release files / neony-0.1.2.tar.gz
| Download URL | neony-0.1.2.tar.gz |
|---|---|
| Size | 211.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b2a986d83000730b53638f50b2e242a623708bf17e7e4f34676578a72bac4616
|
|
BLAKE2b-256 checksum How to use checksums |
f47d2c4afb3f3f4b9de0e93cf767813f8409257a2f7bbfcb0fce278525c4d118
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.
Transparency logRelease files / neony-0.1.2-py3-none-any.whl
| Download URL | neony-0.1.2-py3-none-any.whl |
|---|---|
| Size | 173.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cf04ab86aa0c0c44569da79c9f9a64a414f182641c4ab97340c5cb7df7f05ded
|
|
BLAKE2b-256 checksum How to use checksums |
20ab9c4511f3bbb392173cc96a0d2539fe30dedd79a7e934fc1aef870b5df556
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.
Transparency log