Skip to main content

Neony

Reactive desktop UI framework for Python, built on LumiView.

License: Apache-2.0 Python Status: pre-beta

📖 Docs (latest release): https://harcic.me/neony · 中文

These hosted docs point to the latest tag. For the latest commit (in-repo docs/), see docs/docs/README.en.md, getting-started, api/ chapters.

中文文档 · Contributing


Overview

Status: pre-beta — 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 updates the browser DOM incrementally. Application code does not need to write HTML or JavaScript.

It builds on LumiView, which uses the same Rust tao/wry webview stack as Tauri.

  • Pure Python API — components, layouts and events; no HTML or JavaScript in application code
  • Fine-grained reactivitySignal / Computed / Effect primitives with declarative bindings
  • Same stack as Tauri — Rust tao/wry webviews via LumiView
  • 8 theme presets — Nightglow / Planet Plaza / Ember Zone / Cyberangel families, each with light and dark material, 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). Linux development and verification primarily target Wayland; X11 is not a complete support target at this stage. See the installation and platform guide for system packages and troubleshooting. 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
from neony.dom import Signal

clicks = Signal(0)
counter = Button("Click me")
counter.bind_text(clicks, fmt=lambda count: f"Clicked {count} times!" if count else "Click me")
counter.on_click(lambda _event: clicks.update(lambda count: count + 1))

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
PromptDialog Single-field text prompt on top of Dialog — confirm / cancel, Enter / Escape
Tooltip Hover bubble wrapped around an anchor, placement offsets, hover delay
Dropdown Themed popup under a trigger — full keyboard nav + click-away close
Menu / MenuBranch Fixed popup at the cursor (open_at(x, y) from contextmenu) with cascading branches
CascadingDropdown Multi-level trigger dropdown — nested branches open beside their parent item
Toast Transient notifications at a screen edge — 6 placements, success/info/error, placement-tied directional animations
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 (default; multiple=False is exclusive), expanded_keys, on_change
Tree / TreeNode Collapsible navigation tree + content host — arbitrary depth, fluent builders, leaf selection shows its panel on the right
List / ListItem Scrollable single-select data list — listbox model, arrow keys move selection, selected_key / bind_selected
DataTable / Column Column config + data rows — sticky header, click-to-sort, single / multi row selection
Reorder / ReorderItem Drag-reorder board — any component/DOM element can be a card; direction + wrap makes a grid reorderable on both axes, multiple boards exchange cards
ReorderContent Reorderable container content — drag reorder without a board border/background
Icon One icon — Icon.image(url_or_path) 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 divider — horizontal (default) or vertical
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)
Video / Audio Managed themed media players — custom transport row, local neony:// sources, HEVC transcode fallback
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
MessageBubble chat message — from_me alignment/colors, optional avatar + name, built-in right-click menu, hover quick actions
NoticeBubble Centered system message pill for chat notices
RichText Inline contenteditable editor — text + images, caret/selection API, insert at caret, content() segments, IME-safe, paste image files
ScrollArea Scrollable vertical region with scroll_to_bottom() / scroll_to_top() / scroll_to()
StickToBottom Chat-stream scroll container — auto-pins near the bottom; pauses on scroll-up, resumes near the bottom

All components share a fluent, chainable API — see the API index for usage.


Window Features

  • Frameless custom titlebar — set decorations=False, add a TitleBar, and drag / minimize / maximize / close all work automatically. See docs/api/layout-chrome.en.md and the demo_custom_window.py demo.
  • Transparent windows & native effectstransparent=True automatically applies the platform material (Wayland blur on Linux where the compositor supports it, Acrylic on Windows, Blur on macOS). apply_blur(), apply_acrylic(), and apply_mica() are manual overrides and are platform-limited (apply_blur is macOS/Windows; acrylic / mica are Windows 11). See demo_transparent_panel.py.
  • Programmatic window controlset_title(), set_size(), minimize(), toggle_maximize(), close(), … all on NeonApplication, with window_index=0 for multi-window apps.
  • Clipboardapp.clipboard_write(text) / app.clipboard_read().
  • Local resource URLsfile_url() / data_url() for Windows paths, spaces, and non-ASCII filenames.
  • Custom protocols — serve content to the page via neony://<key>/… URLs: declare handlers with @protocol("key") (plain functions or methods) and pass them to launch(page, protocols=[...]). The built-in local_files handler serves local files over neony://local/… with Range support where file:// is blocked by the webview; local_url(path) / protocol_url(key, value) build the URLs. The managed Video / Audio components hydrate neony:// sources automatically — the webview's media pipeline can't read custom schemes, so the runtime fetches the bytes and swaps in a Blob URL — and local media plays (and seeks) with no extra work. Raw <audio> / <video> DOM elements are not hydrated. See demo_protocols.py.
  • Internationalization — typed catalogs plus tr / set_language(); bound labels update live on a language switch.
  • Multi-windowrun(*pages) opens one window per page, all sharing one event loop and app.state. launch([...]) accepts a list. See demo_multi_window.py.
  • System trayapp.tray = Tray(icon, tooltip, items=[...]) adds a tray icon with a native context menu; close_to_tray=True hides the app instead of quitting on close. Linux needs libayatana-appindicator. See demo_tray.py.
  • Native file dialogsapp.open_file(), app.open_files(), app.save_file(), app.select_folder() shell out to the platform's own picker — zenity on Linux, osascript on macOS, PowerShell on Windows, tkinter fallback — opened asynchronously so the app keeps running while they're up (None on cancel, [] for a cancelled multi-select).

Theming

Eight built-in presets across four visual families — Nightglow, Planet Plaza, Ember Zone, and Cyberangel, each with paired light and dark material — exposed as CSS custom properties on :root; the historical names DARK (default), LIGHT, and DEEP_BLUE remain as aliases. Switching themes replaces the :root variable block, and the browser recolors every var(--color-*). Scrollbars and interaction glows (focus rings, hover halos) reference the same tokens, so they follow theme switches too. See the API reference for switching and custom themes. Motion tokens work the same way: Motion.DEFAULT injects --motion-* variables, with transition() / popup_animation() / submenu_animation() covering common interactions.


Demos

Run from the repository root:

File Shows
demo_hello.py Minimal first app (same as the Quick Start example)
gallery package (uv run gallery) 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 Centered Page mixing components with a raw styled Div
demo_media.py Managed Video / Audio players with media events
demo_protocols.py neony:// custom protocols: local media + dynamic responses
uv run gallery

Roadmap

Planned work lives in ROADMAP.md — performance, events, lifecycle, components, animation, platform integration and verification.


Running the demos from source

The demos in the repository root need the development environment described in CONTRIBUTING.md, then:

uv run gallery

Development, testing and documentation conventions live in the contributing guide.


License

Apache-2.0 © HarcicYang

Release files for neony 0.3.1

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

Source distribution (sdist)

Source distribution for neony 0.3.1
File Size Uploaded
neony-0.3.1.tar.gz 783.7 kB Details

Built distribution (wheel)

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

Total release size: 1.5 MB

Release files / neony-0.3.1.tar.gz

Download URL neony-0.3.1.tar.gz
Size 783.7 kB
Tags Source
SHA-256 checksum
How to use checksums
a8d6566e8261bf73f50e1b48f4609e05f6324ec8eaece120145211de4e33bb59
BLAKE2b-256 checksum
How to use checksums
06133ed5b98cb90e4629b6c89db921bc691567b14e7e95cd28102b2e4b8fdae7
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 27, 2026.

Transparency log

Release files / neony-0.3.1-py3-none-any.whl

Download URL neony-0.3.1-py3-none-any.whl
Size 721.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fb3a78071bd736ea03a6934117eb858f332dfbb5fb4bb3867e52b47104ada35f
BLAKE2b-256 checksum
How to use checksums
43e162a2bf96277c725ed2315961a06bf8c1d060c7344205a08738e3402c21ec
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 27, 2026.

Transparency log
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