# Pyzed: Component library > Pyzed is an open-source (MIT) Python framework for building native desktop GUIs. Python describes the interface; Iced, a GPU-accelerated GUI toolkit written in Rust, lays it out and draws it. It aims to be a frontend framework for desktop apps (mobile and web later), with 90+ components whose look is inspired by the Zed editor, themes, node-based GPU shaders, packaging for every desktop platform and Pyzed Design, a drag-and-drop visual designer in the spirit of Visual Basic, Qt Designer and Godot. ## Component library ### Components > Browse 90+ Pyzed UI components for Python desktop GUIs: buttons, tables, trees, editors, charts and dialogs, each with a preview, examples and its API. Source: https://albakore.github.io/pyzed/library/ Every component of `pyzed.ui`, plus the layout and content widgets of `pyzed`, with a live preview, the code that draws it, examples and its API. Components are **functions that return widgets**, so they combine freely with each other and with the [base widgets](https://albakore.github.io/pyzed/reference/widgets/). ```python import pyzed as pz from pyzed import ui ui.button("Save", self.save, icon="save", variant="solid", keys="ctrl-s") ``` - **Theme colors.** Every component reads the current theme (`App.theme`, or the window's theme in [multi-window](https://albakore.github.io/pyzed/guides/windows/) apps), and accepts `theme=` to use another one. - **Tokens or hex.** Color parameters (`color`, `icon_color`, `tint`…) take a theme token such as `"accent"`, `"text_muted"` or `"error"`, or a `"#rrggbb"` color. - **Messages or callables.** `on_press`, `on_select`, `on_toggle`… take a message for `update` or a callable; those that produce a value (text, `bool`, id) call it with that value. - **Icons.** `icon=` takes any [Lucide](https://lucide.dev) name (`pyzed icons` lists them). To see them all running, open the gallery: `python examples/gallery.py`. Looking for whole screens built from them (login, dashboard, settings, chat, kanban...)? See [Blocks](https://albakore.github.io/pyzed/blocks/). :::note[What is on each page] A short explanation in plain words, a preview with its code, every variant, size and state captured in light and dark with the snippet that draws it, examples, tips and the API table. Pages of interactive components, such as [Button](https://albakore.github.io/pyzed/library/button/) and [Input](https://albakore.github.io/pyzed/library/input/), also show a short recording of them in use. ::: :::tip[Inspiration] The look of these components takes inspiration from the UI of the [Zed](https://zed.dev) editor; the idea of building desktop tools from ready-made pieces comes from Godot, Unreal Engine, Visual Basic and Qt Designer. pyzed is an independent project. ::: #### Actions Buttons and small controls that run something. #### Display Text, badges, keys, avatars and surfaces. #### Forms Controlled inputs: they show your state and report every change. #### Dates and times Calendars and fields for dates, ranges and times, in the format you choose. #### Feedback Progress, loading, notices and empty states. #### Data Tables, numbers and small charts drawn with the theme colors. #### Lists and menus Rows, file trees, context menus and collapsible sections. #### Navigation Tabs, breadcrumbs and toolbars. #### Overlays Things drawn on top of the UI: layers, modals, palettes and notifications. #### Dialogs Ready-made dialogs with translated buttons. #### System Pieces that talk to the operating system: its file dialogs and files dropped from the desktop. #### Workspace The frame of an editor-style window: docks, title bar, status bar and panels. #### Code and tools The code editor, a terminal view, a log console and help boxes. #### AI agents The pieces of an AI agent's chat and settings: tool calls, diffs, plans, history and sign-in. #### Layout The base layout widgets of `pyzed` (`pz.*`) every component is built with. #### Content Base widgets for text, icons, images, Markdown, QR codes and drawing. ### Events of every component > Every event of every Pyzed component: what each one reports, what the handler gets, and how many events each component can have. Source: https://albakore.github.io/pyzed/library/events/ Pyzed widgets react to events in two layers: - **Their own events**: the `on_*` parameters of each component, such as `on_press` of a button or `on_select` of a tree. They report what the component means (a tab was closed, a row was opened) and usually pass a value (the text, the item, the new state). - **The common events**: 18 events every widget has, whatever it is, attached with `.on(...)`: clicks, hover, drag, focus, keys and size. A `pz.Component` also raises `on_mount` and `on_unmount`. So a component can have up to its own events plus 18 common ones. Across the 114 components of the library there are **160 own events**; the ones with the most are listed first in the table at the end. ```python ui.list_item("main.py", self.open, icon="file").on( # on_press is its own event right_click=self.show_menu, # the common ones: any widget mouse_enter=lambda: setattr(self, "hovered", "main.py"), drag=lambda e: self.move(e.dx, e.dy), # takes the pz.Event ) ``` #### The common events Every widget has them. A handler without arguments is called with nothing; one with an argument gets a `pz.Event`. | Group | Event | When | | --- | --- | --- | | Mouse | `click` | The widget was clicked (pressed and released with the left button). | | Mouse | `double_click` | Two clicks in quick succession. | | Mouse | `right_click` | The right button was pressed (use it for context menus). | | Mouse | `middle_click` | The middle button (wheel) was pressed. | | Mouse | `mouse_down` | Any button was pressed over the widget (`event.button`). | | Mouse | `mouse_up` | Any button was released over the widget (`event.button`). | | Mouse | `mouse_enter` | The pointer moved onto the widget. | | Mouse | `mouse_leave` | The pointer left the widget. | | Mouse | `mouse_move` | The pointer moved over the widget (`event.x`, `event.y`). | | Mouse | `scroll` | The wheel turned over the widget (`event.dx`, `event.dy` in lines). | | Drag | `drag_start` | The left button was pressed and the pointer moved a few pixels. | | Drag | `drag` | The pointer moved while dragging (`event.dx`, `event.dy` since the last one). | | Drag | `drag_end` | The button was released after a drag. | | Focus | `focus` | The widget was clicked and now receives key events. | | Focus | `blur` | A click elsewhere took the focus away. | | Keyboard | `key_down` | A key was pressed while focused (`event.key`, e.g. `"ctrl-s"`). | | Keyboard | `key_up` | A key was released while focused (`event.key`). | | Layout | `resize` | The widget got a new size, including its first one (`event.width`, `event.height`). | ##### Fields of `pz.Event` | Property | Description | | --- | --- | | `type` | The event name (`"click"`, or a component's own event). | | `x`, `y` | Pointer position relative to the widget (`position` gives both). | | `window_x`, `window_y` | Pointer position in the window. | | `screen_x`, `screen_y` | On the screen (`None` where the system does not say, such as Wayland). | | `dx`, `dy` | Scroll amount, or drag movement since the previous `drag`. | | `width`, `height` | The widget's size (`size` gives both). | | `button` | `"left"`, `"right"`, `"middle"`… | | `key` | The key combo, such as `"ctrl-s"`. | | `shift`, `ctrl`, `alt`, `logo` | Modifiers held. | | `value`, `source` | For a component's own events: the data and the component. | #### What handlers get Controls that produce a value call your callable with it. The most common shapes: | Handler | Description | Events | | --- | --- | --- | | `()` | Nothing: the event is the news (a press, a close, Enter). | `ui.alert(on_close=)`, `ui.badge(on_press=)`, `ui.breadcrumbs(on_more=)`, `ui.button(on_press=)`… | | `(event)` | A `pz.Event`: its `value` holds the data, `source` the component. | `ui.Calendar(on_change=)`, `ui.Calendar(on_month=)`, `ui.Catalog(on_install=)`, `ui.ColorPicker(on_change=)`… | | `(text)` | The new text, on every keystroke. | `ui.command_palette(on_query=)`, `ui.console(on_query=)`, `ui.editor(on_change=)`, `ui.input(on_input=)`… | | `(x, y)` | The pointer position, relative to the widget. | `pz.canvas(on_press=)`, `pz.canvas(on_release=)`, `pz.canvas(on_right_press=)`, `pz.canvas(on_move=)`… | | `(info)` | A dict (scroll offset and sizes) or a `ui.ErrorInfo`. | `ui.editor(on_scroll=)`, `ui.error_boundary(on_error=)`, `ui.error_boundary(on_details=)`, `pz.scrollable(on_scroll=)`… | | `(value)` | The new value: a number, a color, an option… | `ui.file_input(on_change=)`, `ui.number_field(on_change=)`, `ui.radio_group(on_select=)`, `ui.slider(on_change=)`… | | `(tab_id)` | The id of the tab. | `ui.tab_bar(on_select=)`, `ui.tab_bar(on_close=)`, `ui.tab_bar(on_drag=)`, `ui.tab_bar(on_context=)` | | `(id)` | The id of the row or tab (for a tree, its path). | `ui.tree(on_toggle=)`, `ui.tree(on_select=)`, `ui.tree(on_open=)`, `ui.tree(on_context=)` | | `(row)` | The row (the dict or object you passed in `rows`). | `ui.table(on_row_press=)`, `ui.table(on_row_double_press=)`, `ui.table(on_row_context=)` | | `(dx, dy)` | How far the wheel turned, in lines. | `pz.canvas(on_scroll=)`, `pz.mouse_area(on_scroll=)` | | `(checked)` | The new state, `True` or `False`. | `ui.checkbox(on_toggle=)`, `ui.switch(on_toggle=)` | | `(line)` | The log line (a `ui.LogEntry`). | `ui.console(on_context=)`, `ui.console(on_open=)` | | `(name)` | A name: of the icon, or of the editor action. | `ui.editor(on_action=)`, `ui.icon_picker_dialog(on_pick=)` | | `(url)` | The URL of the link. | `ui.markdown(on_link=)`, `ui.reference_browser(on_open_url=)` | | `(size)` | The new size in pixels, when a drag ends. | `ui.panel(on_resize=)`, `pz.resizable(on_resize=)` | | `(item)` | The option that was chosen. | `ui.segmented(on_select=)`, `ui.select(on_select=)` | #### Events of each component **Own** counts the component's `on_*` events; **Total** adds the 18 common ones (and `mount` / `unmount` for `pz.Component` classes). | Component | Own | Total | Its events | | --- | --- | --- | --- | | [Mouse area](https://albakore.github.io/pyzed/library/mouse-area/#events) | 10 | 28 | `on_press`, `on_release`, `on_right_press`, `on_double_click`, `on_enter`, `on_exit`, `on_move`, `on_scroll`, `on_middle_press`, `on_middle_release` | | [Console](https://albakore.github.io/pyzed/library/console/#events) | 8 | 26 | `on_query`, `on_toggle_level`, `on_clear`, `on_copy`, `on_context`, `on_open`, `on_source`, `on_write` | | [Tab bar](https://albakore.github.io/pyzed/library/tab-bar/#events) | 7 | 25 | `on_select`, `on_close`, `on_drag`, `on_drop`, `on_drag_over`, `on_context`, `on_new` | | [Editor](https://albakore.github.io/pyzed/library/editor/#events) | 6 | 24 | `on_change`, `on_cursor`, `on_scroll`, `on_zoom`, `on_action`, `on_hover` | | [Canvas](https://albakore.github.io/pyzed/library/canvas/#events) | 5 | 23 | `on_press`, `on_release`, `on_right_press`, `on_move`, `on_scroll` | | [Drop zone](https://albakore.github.io/pyzed/library/drop-zone/#events) | 5 | 25 | `on_drop`, `on_files`, `on_reject`, `on_enter`, `on_leave` | | [Edits bar](https://albakore.github.io/pyzed/library/edits-bar/#events) | 5 | 25 | `on_keep`, `on_reject`, `on_keep_file`, `on_reject_file`, `on_open` | | [Window frame](https://albakore.github.io/pyzed/library/window-frame/#events) | 5 | 23 | `on_drag`, `on_minimize`, `on_maximize`, `on_close`, `on_menu` | | [Date picker](https://albakore.github.io/pyzed/library/date-picker/#events) | 4 | 24 | `on_change`, `on_open`, `on_close`, `on_dismiss` | | [Sign-in prompt](https://albakore.github.io/pyzed/library/auth-prompt/#events) | 4 | 24 | `on_pick`, `on_cancel`, `on_open_url`, `on_copy` | | [Table](https://albakore.github.io/pyzed/library/table/#events) | 4 | 22 | `on_sort`, `on_row_press`, `on_row_double_press`, `on_row_context` | | [Tree](https://albakore.github.io/pyzed/library/tree/#events) | 4 | 22 | `on_toggle`, `on_select`, `on_open`, `on_context` | | [Command palette](https://albakore.github.io/pyzed/library/command-palette/#events) | 3 | 21 | `on_query`, `on_submit`, `on_press` | | [Date range picker](https://albakore.github.io/pyzed/library/date-range-picker/#events) | 3 | 23 | `on_change`, `on_open`, `on_close` | | [Error dialog](https://albakore.github.io/pyzed/library/error-dialog/#events) | 3 | 21 | `on_close`, `on_go_to`, `on_logs` | | [Icon picker](https://albakore.github.io/pyzed/library/icon-picker/#events) | 3 | 23 | `on_change`, `on_pick`, `on_close` | | [Input](https://albakore.github.io/pyzed/library/input/#events) | 3 | 21 | `on_input`, `on_submit`, `on_clear` | | [List item](https://albakore.github.io/pyzed/library/list-item/#events) | 3 | 21 | `on_press`, `on_right_press`, `on_double_press` | | [Prompt](https://albakore.github.io/pyzed/library/prompt/#events) | 3 | 21 | `on_input`, `on_submit`, `on_cancel` | | [Select](https://albakore.github.io/pyzed/library/select/#events) | 3 | 21 | `on_select`, `on_open`, `on_close` | | [Time picker](https://albakore.github.io/pyzed/library/time-picker/#events) | 3 | 23 | `on_change`, `on_open`, `on_close` | | [Tool call](https://albakore.github.io/pyzed/library/tool-call/#events) | 3 | 23 | `on_allow`, `on_allow_always`, `on_deny` | | [Unsaved changes](https://albakore.github.io/pyzed/library/unsaved-changes/#events) | 3 | 21 | `on_save`, `on_discard`, `on_cancel` | | [Breadcrumbs](https://albakore.github.io/pyzed/library/breadcrumbs/#events) | 2 | 20 | `on_press`, `on_more` | | [Calendar](https://albakore.github.io/pyzed/library/calendar/#events) | 2 | 22 | `on_change`, `on_month` | | [Chip](https://albakore.github.io/pyzed/library/chip/#events) | 2 | 20 | `on_press`, `on_remove` | | [Color picker](https://albakore.github.io/pyzed/library/color-picker/#events) | 2 | 22 | `on_change`, `on_press` | | [Confirm](https://albakore.github.io/pyzed/library/confirm/#events) | 2 | 20 | `on_confirm`, `on_cancel` | | [Error boundary](https://albakore.github.io/pyzed/library/error-boundary/#events) | 2 | 20 | `on_error`, `on_details` | | [Number field](https://albakore.github.io/pyzed/library/number-field/#events) | 2 | 20 | `on_change`, `on_submit` | | [Picker](https://albakore.github.io/pyzed/library/picker/#events) | 2 | 20 | `on_query`, `on_submit` | | [Service row](https://albakore.github.io/pyzed/library/service-row/#events) | 2 | 22 | `on_toggle`, `on_primary` | | [Slider](https://albakore.github.io/pyzed/library/slider/#events) | 2 | 20 | `on_change`, `on_release` | | [Split button](https://albakore.github.io/pyzed/library/split-button/#events) | 2 | 20 | `on_press`, `on_menu` | | [Thread history](https://albakore.github.io/pyzed/library/thread-history/#events) | 2 | 22 | `on_open`, `on_delete` | | [Toast](https://albakore.github.io/pyzed/library/toast/#events) | 2 | 20 | `on_dismiss`, `on_press` | | [Accordion](https://albakore.github.io/pyzed/library/accordion/#events) | 1 | 19 | `on_toggle` | | [Alert](https://albakore.github.io/pyzed/library/alert/#events) | 1 | 19 | `on_close` | | [Badge](https://albakore.github.io/pyzed/library/badge/#events) | 1 | 19 | `on_press` | | [Button](https://albakore.github.io/pyzed/library/button/#events) | 1 | 19 | `on_press` | | [Callout](https://albakore.github.io/pyzed/library/callout/#events) | 1 | 19 | `on_dismiss` | | [Card](https://albakore.github.io/pyzed/library/card/#events) | 1 | 19 | `on_press` | | [Catalog](https://albakore.github.io/pyzed/library/catalog/#events) | 1 | 21 | `on_install` | | [Checkbox](https://albakore.github.io/pyzed/library/checkbox/#events) | 1 | 19 | `on_toggle` | | [Choice](https://albakore.github.io/pyzed/library/choice/#events) | 1 | 19 | `on_cancel` | | [Dialog layer](https://albakore.github.io/pyzed/library/dialog-layer/#events) | 1 | 19 | `on_dismiss` | | [Disclosure](https://albakore.github.io/pyzed/library/disclosure/#events) | 1 | 19 | `on_toggle` | | [File picker](https://albakore.github.io/pyzed/library/file-input/#events) | 1 | 19 | `on_change` | | [Icon button](https://albakore.github.io/pyzed/library/icon-button/#events) | 1 | 19 | `on_press` | | [Layer](https://albakore.github.io/pyzed/library/layer/#events) | 1 | 19 | `on_dismiss` | | [Markdown](https://albakore.github.io/pyzed/library/markdown/#events) | 1 | 19 | `on_link` | | [Menu](https://albakore.github.io/pyzed/library/menu/#events) | 1 | 19 | `on_press` | | [Modal](https://albakore.github.io/pyzed/library/modal/#events) | 1 | 19 | `on_close` | | [Panel](https://albakore.github.io/pyzed/library/panel/#events) | 1 | 19 | `on_resize` | | [Popover](https://albakore.github.io/pyzed/library/popover/#events) | 1 | 19 | `on_dismiss` | | [Radio group](https://albakore.github.io/pyzed/library/radio-group/#events) | 1 | 19 | `on_select` | | [Reference browser](https://albakore.github.io/pyzed/library/reference-browser/#events) | 1 | 19 | `on_open_url` | | [Resizable](https://albakore.github.io/pyzed/library/resizable/#events) | 1 | 19 | `on_resize` | | [Scrollable](https://albakore.github.io/pyzed/library/scrollable/#events) | 1 | 19 | `on_scroll` | | [Search input](https://albakore.github.io/pyzed/library/search-input/#events) | 1 | 19 | `on_input` | | [Segmented](https://albakore.github.io/pyzed/library/segmented/#events) | 1 | 19 | `on_select` | | [Shortcuts](https://albakore.github.io/pyzed/library/shortcuts/#events) | 1 | 19 | `on_query` | | [Split](https://albakore.github.io/pyzed/library/split/#events) | 1 | 19 | `on_resize` | | [Stat](https://albakore.github.io/pyzed/library/stat/#events) | 1 | 19 | `on_press` | | [Status bar](https://albakore.github.io/pyzed/library/status-bar/#events) | 1 | 19 | `on_press` | | [Switch](https://albakore.github.io/pyzed/library/switch/#events) | 1 | 19 | `on_toggle` | | [Title bar](https://albakore.github.io/pyzed/library/title-bar/#events) | 1 | 19 | `on_press` | | [Toggle group](https://albakore.github.io/pyzed/library/toggle-group/#events) | 1 | 19 | `on_select` | | [Virtual list](https://albakore.github.io/pyzed/library/virtual-list/#events) | 1 | 19 | `on_scroll` | | [Workspace](https://albakore.github.io/pyzed/library/workspace/#events) | 1 | 19 | `on_resize` | | [About](https://albakore.github.io/pyzed/library/about/#events) | 0 | 18 | — | | [Anchor layout](https://albakore.github.io/pyzed/library/anchor-layout/#events) | 0 | 18 | — | | [Animation](https://albakore.github.io/pyzed/library/animation/#events) | 0 | 18 | — | | [Avatar](https://albakore.github.io/pyzed/library/avatar/#events) | 0 | 18 | — | | [Bar chart](https://albakore.github.io/pyzed/library/bar-chart/#events) | 0 | 18 | — | | [Column](https://albakore.github.io/pyzed/library/column/#events) | 0 | 18 | — | | [Container](https://albakore.github.io/pyzed/library/container/#events) | 0 | 18 | — | | [Context meter](https://albakore.github.io/pyzed/library/context-meter/#events) | 0 | 18 | — | | [Count badge](https://albakore.github.io/pyzed/library/count-badge/#events) | 0 | 18 | — | | [Diff stat](https://albakore.github.io/pyzed/library/diff-stat/#events) | 0 | 18 | — | | [Diff view](https://albakore.github.io/pyzed/library/diff-view/#events) | 0 | 18 | — | | [Divider](https://albakore.github.io/pyzed/library/divider/#events) | 0 | 18 | — | | [Donut](https://albakore.github.io/pyzed/library/donut/#events) | 0 | 18 | — | | [Effects](https://albakore.github.io/pyzed/library/effects/#events) | 0 | 18 | — | | [Empty state](https://albakore.github.io/pyzed/library/empty-state/#events) | 0 | 18 | — | | [Facepile](https://albakore.github.io/pyzed/library/facepile/#events) | 0 | 18 | — | | [Field](https://albakore.github.io/pyzed/library/field/#events) | 0 | 18 | — | | [Flex](https://albakore.github.io/pyzed/library/flex/#events) | 0 | 18 | — | | [Grid](https://albakore.github.io/pyzed/library/grid/#events) | 0 | 18 | — | | [Heading](https://albakore.github.io/pyzed/library/heading/#events) | 0 | 18 | — | | [Icon](https://albakore.github.io/pyzed/library/icon/#events) | 0 | 18 | — | | [Image](https://albakore.github.io/pyzed/library/image/#events) | 0 | 18 | — | | [Indicator](https://albakore.github.io/pyzed/library/indicator/#events) | 0 | 18 | — | | [Kbd](https://albakore.github.io/pyzed/library/kbd/#events) | 0 | 18 | — | | [Keybinding hint](https://albakore.github.io/pyzed/library/keybinding-hint/#events) | 0 | 18 | — | | [Label](https://albakore.github.io/pyzed/library/label/#events) | 0 | 18 | — | | [List header](https://albakore.github.io/pyzed/library/list-header/#events) | 0 | 18 | — | | [Panel header](https://albakore.github.io/pyzed/library/panel-header/#events) | 0 | 18 | — | | [Plan](https://albakore.github.io/pyzed/library/plan/#events) | 0 | 20 | — | | [Progress](https://albakore.github.io/pyzed/library/progress/#events) | 0 | 18 | — | | [QR code](https://albakore.github.io/pyzed/library/qr-code/#events) | 0 | 18 | — | | [Responsive](https://albakore.github.io/pyzed/library/responsive/#events) | 0 | 18 | — | | [Rich text](https://albakore.github.io/pyzed/library/rich-text/#events) | 0 | 18 | — | | [Row](https://albakore.github.io/pyzed/library/row/#events) | 0 | 18 | — | | [Settings group](https://albakore.github.io/pyzed/library/settings-group/#events) | 0 | 18 | — | | [Shader](https://albakore.github.io/pyzed/library/shader/#events) | 0 | 18 | — | | [Space](https://albakore.github.io/pyzed/library/spacing/#events) | 0 | 18 | — | | [Sparkline](https://albakore.github.io/pyzed/library/sparkline/#events) | 0 | 18 | — | | [Spinner](https://albakore.github.io/pyzed/library/spinner/#events) | 0 | 18 | — | | [Stack](https://albakore.github.io/pyzed/library/stack/#events) | 0 | 18 | — | | [Terminal](https://albakore.github.io/pyzed/library/terminal/#events) | 0 | 18 | — | | [Text](https://albakore.github.io/pyzed/library/text/#events) | 0 | 18 | — | | [Toolbar](https://albakore.github.io/pyzed/library/toolbar/#events) | 0 | 18 | — | | [Tooltip](https://albakore.github.io/pyzed/library/tooltip/#events) | 0 | 18 | — | Next: [App, windows, forms and components](https://albakore.github.io/pyzed/guides/classes/) explains how to create your own events, and [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/) shows the three ways of handling them. ### About > An About box with icon, version, details and links. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/about/ :::tip[In plain words] The “About this app” box: name, version and links. ::: An About box: an icon, the app name and version, a description, a few `(label, value)` details and link buttons. `ui.about` · Category: [Code and tools](https://albakore.github.io/pyzed/library/#code-and-tools) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#about) **Code:** ```python ui.about("Notes", "1.2.0", "A small notes app built with Pyzed.", icon="notebook-pen", details=[("Python", "3.12"), ("Pyzed", "0.4")], links=[("Website", on_website), ("GitHub", on_github)]) ``` #### When to use - In a `ui.modal` opened from the Help menu. #### Usage ```python from pyzed import ui ui.about("Notes", "1.2.0", "A small notes app built with Pyzed.", icon="notebook-pen", details=[("Python", "3.12"), ("Pyzed", "0.4")], links=[("Website", on_website), ("GitHub", on_github)]) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python ui.about("Notes", "1.2.0") ``` ```python ui.about("Notes", "1.2.0", "A small notes app.", icon="notebook-pen", details=[("Python", "3.12"), ("Pyzed", "0.4")]) ``` ```python ui.about("Notes", "1.2.0", icon="notebook-pen", links=[("Website", on_web), ("GitHub", on_gh)]) ``` #### Events About has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.about` ```python about( name, version='', description='', *, icon='app-window', details=(), links=(), theme=None, ) ``` An About box: icon, name, version, a description, a few details and link buttons. | Property | Default | Description | | --- | --- | --- | | `name` | *required* | App name. | | `version` | `""` | Version text. | | `description` | `""` | One or two sentences. | | `icon` | `"app-window"` | Lucide icon. | | `details` | `()` | `(label, value)` rows. | | `links` | `()` | `(label, on_press)` buttons. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#about) #### Related - [Modal](https://albakore.github.io/pyzed/library/modal/): A dialog surface with title, content and footer buttons. - [Shortcuts](https://albakore.github.io/pyzed/library/shortcuts/): A searchable list of key bindings, grouped. ### Accordion > Stacked collapsible sections, like the panels of a settings screen. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/accordion/ :::tip[In plain words] Several sections stacked up, each one opens or closes when you click its title. ::: Stacked collapsible sections separated by dividers. Sections are `(key, title, content)` tuples or `ui.AccordionSection` objects (with `icon` and a header `end` widget). You own the open state: `open` is a set of keys, a `{key: bool}` dict or `True`, and `on_toggle` receives the key. `ui.accordion` · Category: [Lists and menus](https://albakore.github.io/pyzed/library/#lists-and-menus) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#accordion) **Code:** ```python rows = lambda *items: pz.column([ui.field(k, ui.switch(v, on_toggle)) for k, v in items], spacing=8) pz.container(ui.accordion([ ("editor", "Editor", rows(("Soft wrap", True), ("Minimap", False))), ("files", "Files", rows(("Autosave", True))), ("git", "Git", ui.muted("Collapsed sections only show their header.")), ], open={"editor", "files"}, on_toggle=on_toggle, icons={"editor": "file-code", "files": "folder", "git": "git-branch"}), width=400) ``` #### When to use - For long settings or property panels where users only need a few sections at a time. - For a single collapsible block, use a [Disclosure](https://albakore.github.io/pyzed/library/disclosure/). #### Usage ```python import pyzed as pz from pyzed import ui class Settings(pz.App): def __init__(self): self.open = {"editor"} def view(self): return ui.accordion( [("editor", "Editor", ui.muted("…")), ("files", "Files", ui.muted("…"))], open=self.open, on_toggle=lambda key: self.open.symmetric_difference_update({key}), ) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Open sections ```python pz.container(ui.accordion([("a", "Editor", ui.muted("…")), ("b", "Files", ui.muted("…")), ("c", "Git", ui.muted("…"))], open=set(), on_toggle=on_toggle), width=320) ``` ```python pz.container(ui.accordion([("a", "Editor", ui.muted("Font, wrapping, minimap.")), ("b", "Files", ui.muted("…"))], open={"a"}, on_toggle=on_toggle), width=320) ``` ```python pz.container(ui.accordion([("a", "Editor", ui.muted("Font, wrapping.")), ("b", "Files", ui.muted("Autosave."))], open=True, on_toggle=on_toggle), width=320) ``` ##### Content ```python pz.container(ui.accordion([("e", "Editor", ui.muted("…")), ("g", "Git", ui.muted("…"))], open=set(), icons={"e": "file-code", "g": "git-branch"}, on_toggle=on_toggle), width=320) ``` ```python pz.container(ui.accordion([ui.AccordionSection("p", "Problems", ui.muted("…"), icon="circle-x", end=ui.count_badge(3, tint="error"))], open=set(), on_toggle=on_toggle), width=320) ``` #### Events Accordion has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_toggle` | `(key)` | Called with the key of the clicked header. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Settings(pz.App): def __init__(self): self.open = {"editor"} def toggle(self, key): # on_toggle: the key of the clicked header self.open ^= {key} def view(self): return ui.accordion([("editor", "Editor", ui.muted("Font, tabs, wrapping")), ("files", "Files", ui.muted("Autosave, encoding"))], open=self.open, on_toggle=self.toggle) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Toggle: key: str class Settings(pz.App): open = frozenset({"editor"}) def update(self, message): match message: case Toggle(key): self.open = self.open ^ {key} def view(self): return ui.accordion([("editor", "Editor", ui.muted("…")), ("files", "Files", ui.muted("…"))], open=self.open, on_toggle=Toggle) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: open: frozenset = frozenset({"editor"}) def view(state, set_state): return ui.accordion([("editor", "Editor", ui.muted("…")), ("files", "Files", ui.muted("…"))], open=state.open, on_toggle=lambda key: set_state(open=state.open ^ {key})) ``` #### Properties and API ##### `ui.accordion` ```python accordion( sections, *, open=(), on_toggle=None, icons=None, spacing=8, padding=(6, 12, 10, 12), theme=None, ) ``` Stacked collapsible sections separated by dividers, like the panels of a settings screen. Each header spans the whole width, so the content lines up with the rest of the panel. You own the open state: change it in `on_toggle`. | Property | Default | Description | | --- | --- | --- | | `sections` | *required* | `ui.AccordionSection(key, title, content, icon=None, end=None)` items (or `(key, title, content)` tuples). | | `open` | `()` | The set of open ids, a `{id: bool}` dict, or `True` for all. | | `icons` | `None` | `{id: icon}`: a Lucide icon for each header. | | `spacing` | `8` | Space around the dividers between sections. | | `padding` | `(6, 12, 10, 12)` | Padding around the content of an open section. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_toggle` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#accordion) ##### `ui.AccordionSection` ```python class AccordionSection ``` One section of `ui.accordion`: `key`, `title`, `content` and optional `icon` and header `end` widget. | Property | Default | Description | | --- | --- | --- | | `key` | *required* | Key that identifies the subscription (defaults to the message or the function). | | `title` | *required* | Title. | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `end` | `None` | Widgets at the end (right). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#accordionsection) #### Related - [Disclosure](https://albakore.github.io/pyzed/library/disclosure/): One collapsible section with an arrow. - [Settings group](https://albakore.github.io/pyzed/library/settings-group/): A titled block of field rows, for settings screens. ### Alert > A message with one button. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/alert/ :::tip[In plain words] A message box with a single OK button. ::: A message with a single OK button. `kind` (`"info"`, `"success"`, `"warning"`, `"error"`) adds an icon. `ui.alert` · Category: [Dialogs](https://albakore.github.io/pyzed/library/#dialogs) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#alert) **Code:** ```python ui.dialog_layer(main_view(), ui.alert("The export finished: 128 files were written.", on_close, title="Export", kind="success", width=360)) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - To report something the user must acknowledge (an export finished, a file could not be opened). #### Usage ```python from pyzed import ui ui.dialog_layer(main_view(), ui.alert("The export finished: 128 files were written.", on_close, title="Export", kind="success", width=360)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Kind ```python ui.alert("The file was moved to the trash.", on_close, width=320) ``` ```python ui.alert("A new version is available.", on_close, kind="info", width=320) ``` ```python ui.alert("128 files were exported.", on_close, kind="success", title="Export", width=320) ``` ```python ui.alert("The disk is almost full.", on_close, kind="warning", width=320) ``` ```python ui.alert("notes.py could not be opened.", on_close, kind="error", title="Error", width=320) ``` ##### Options ```python ui.alert("Shortcuts changed in this version.", on_close, ok_label="Got it", width=320) ``` #### Events Alert has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_close` | `()` | The button and the close icon. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Export(pz.App): def __init__(self): self.done = True def view(self): alert = ui.alert("128 files were written.", lambda: setattr(self, "done", False), # on_close title="Export", kind="success") return ui.dialog_layer(main_view(), alert if self.done else None) ``` **Declarative:** ```python class Export(pz.App): done = True def update(self, message): if message == "ok": self.done = False def view(self): return ui.dialog_layer(main_view(), ui.alert("128 files were written.", "ok", title="Export") if self.done else None) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: done: bool = True def view(state, set_state): alert = ui.alert("128 files were written.", lambda: set_state(done=False), title="Export") return ui.dialog_layer(main_view(), alert if state.done else None) ``` #### Properties and API ##### `ui.alert` ```python alert(message, on_close, *, title=None, kind=None, ok_label=None, width=400, theme=None) ``` A message with one button. | Property | Default | Description | | --- | --- | --- | | `message` | *required* | Text or widget. | | `title` | `None` | Title. | | `kind` | `None` | `"info"`, `"success"`, `"warning"` or `"error"` adds an icon. | | `ok_label` | `None` | Button text (default: OK, translated). | | `width` | `400` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_close` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#alert) #### Related - [Confirm](https://albakore.github.io/pyzed/library/confirm/): A yes/no question, red for destructive actions. - [Dialog layer](https://albakore.github.io/pyzed/library/dialog-layer/): Centers a dialog over your view with a dimmed backdrop. - [Toast](https://albakore.github.io/pyzed/library/toast/): Notifications stacked in the bottom-right corner. ### Anchor layout > Free positions like a form designer, with anchors that follow resizes. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/anchor-layout/ :::tip[In plain words] Places things exactly where you put them, and says which corner each one sticks to when the window grows. ::: Places children at exact positions, the way a visual form designer does, and says how each one follows a resize: `pz.anchor(child, x=, y=, width=, height=, anchor=)` keeps the distance to the edges it is anchored to, stretches between opposite edges and stays centered otherwise. Presets such as `"top_right"`, `"bottom_wide"`, `"center"` or `"full"` cover the usual cases. `pyzed.anchors.place` is the math behind it, for your own layouts. `pz.anchor_layout` · Category: [Layout](https://albakore.github.io/pyzed/library/#layout) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#anchor_layout) **Code:** ```python t = pz.theme.current() pz.container(pz.anchor_layout([ pz.anchor(ui.heading("Report", level=3), x=16, y=12, width=200, height=28, anchor="top_left"), pz.anchor(ui.icon_button("x", on_close), x=356, y=12, width=28, height=28, anchor="top_right"), pz.anchor(ui.input("", on_input, placeholder="Search…"), x=16, y=56, width=368, height=30, anchor="top_wide"), pz.anchor(ui.button("Close", on_close, variant="solid"), x=284, y=172, width=100, height=30, anchor="bottom_right"), ], design=(400, 216)), width=400, height=216, bg=t.panel, border_color=t.border, border_width=1, radius=8) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For forms drawn in Pyzed Design (it is what the Form view generates) or ported from Visual Basic, Qt Designer or WinForms. - For game HUDs and overlays where things stick to corners. - For forms that grow and shrink with the window, prefer `row`, `column` and `grid`. #### Usage ```python import pyzed as pz from pyzed import ui class Report(pz.App): def view(self): return pz.anchor_layout([ pz.anchor(ui.heading("Report"), x=16, y=12, width=368, height=28, anchor="top_wide"), pz.anchor(self.table(), x=16, y=48, width=368, height=196, anchor="full"), pz.anchor(ui.button("Close", self.close), x=284, y=252, width=100, height=32, anchor="bottom_right"), ], design=(400, 300)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Presets Each layout was designed at 110 × 44 and drawn at 260 × 110: the badge keeps its distance to the edges it is anchored to. ```python t = pz.theme.current() pz.container(pz.anchor_layout([pz.anchor(ui.badge("top_left"), x=10, y=10, width=90, height=24, anchor="top_left")], design=(110, 44)), width=260, height=110, border_color=t.border, border_width=1, radius=8) ``` ```python t = pz.theme.current() pz.container(pz.anchor_layout([pz.anchor(ui.badge("top_right"), x=10, y=10, width=90, height=24, anchor="top_right")], design=(110, 44)), width=260, height=110, border_color=t.border, border_width=1, radius=8) ``` ```python t = pz.theme.current() pz.container(pz.anchor_layout([pz.anchor(ui.badge("bottom_left"), x=10, y=10, width=90, height=24, anchor="bottom_left")], design=(110, 44)), width=260, height=110, border_color=t.border, border_width=1, radius=8) ``` ```python t = pz.theme.current() pz.container(pz.anchor_layout([pz.anchor(ui.badge("bottom_right"), x=10, y=10, width=90, height=24, anchor="bottom_right")], design=(110, 44)), width=260, height=110, border_color=t.border, border_width=1, radius=8) ``` ```python t = pz.theme.current() pz.container(pz.anchor_layout([pz.anchor(ui.badge("center"), x=10, y=10, width=90, height=24, anchor="center")], design=(110, 44)), width=260, height=110, border_color=t.border, border_width=1, radius=8) ``` ##### Stretching ```python t = pz.theme.current() pz.container(pz.anchor_layout([pz.anchor(pz.container(width="fill", height="fill", bg=t.accent, radius=4), x=10, y=10, width=90, height=24, anchor="top_wide")], design=(110, 44)), width=260, height=110, border_color=t.border, border_width=1, radius=8) ``` ```python t = pz.theme.current() pz.container(pz.anchor_layout([pz.anchor(pz.container(width="fill", height="fill", bg=t.accent, radius=4), x=10, y=10, width=90, height=24, anchor="bottom_wide")], design=(110, 44)), width=260, height=110, border_color=t.border, border_width=1, radius=8) ``` ```python t = pz.theme.current() pz.container(pz.anchor_layout([pz.anchor(pz.container(width="fill", height="fill", bg=t.accent, radius=4), x=10, y=10, width=90, height=24, anchor="left_tall")], design=(110, 44)), width=260, height=110, border_color=t.border, border_width=1, radius=8) ``` ```python t = pz.theme.current() pz.container(pz.anchor_layout([pz.anchor(pz.container(width="fill", height="fill", bg=t.accent, radius=4), x=10, y=10, width=90, height=24, anchor="center_wide")], design=(110, 44)), width=260, height=110, border_color=t.border, border_width=1, radius=8) ``` ```python t = pz.theme.current() pz.container(pz.anchor_layout([pz.anchor(pz.container(width="fill", height="fill", bg=t.accent, radius=4), x=10, y=10, width=90, height=24, anchor="full")], design=(110, 44)), width=260, height=110, border_color=t.border, border_width=1, radius=8) ``` #### Events Anchor layout has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Tips :::tip `design` is the size the positions were measured in; when the layout gets more or less room, each child moves or stretches from there. Try it live: drag the window corner of a form in Pyzed Design. ::: #### Properties and API ##### `pz.anchor_layout` ```python anchor_layout(children, *, design=None, width='fill', height='fill') ``` Places children made with `pz.anchor` freely, like a designed form: when it is resized, each child keeps its distance to the edges it is anchored to, stretches between opposite ones and stays centered otherwise. Later children are drawn on top. See [Anchored layouts](https://albakore.github.io/pyzed/guides/layout/#anchored-layouts). | Property | Default | Description | | --- | --- | --- | | `children` | *required* | Children made with `pz.anchor(...)` (`None` is skipped). | | `design` | `None` | `(width, height)` the children were laid out in; by default the smallest size that holds them. | | `width` | `"fill"` | Width. | | `height` | `"fill"` | Height. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#anchor_layout) ##### `pz.anchor` ```python anchor( content, *, x=0, y=0, width=100, height=28, anchor='top_left', min_width=0, min_height=0, max_width=0, max_height=0, pivot=(0.5, 0.5), rotate=0, ) ``` Places a child of `pz.anchor_layout` at `x`, `y` with `width` and `height` (in the layout's design size) and says how it follows a resize. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | The widget. | | `x` | `0` | Left edge in the design size. | | `y` | `0` | Top edge in the design size. | | `width` | `100` | Width in the design size. | | `height` | `28` | Height in the design size. | | `anchor` | `"top_left"` | A preset of `pyzed.anchors.PRESETS` (`"top_right"`, `"bottom_wide"`, `"center"`, `"full"`...), words (`"left right bottom"`) or a tuple of edges. | | `min_width` | `0` | Smallest width when it stretches (`0`: no limit). | | `min_height` | `0` | Smallest height when it stretches. | | `max_width` | `0` | Largest width when it stretches (`0`: no limit). | | `max_height` | `0` | Largest height when it stretches. | | `pivot` | `(0.5, 0.5)` | `(x, y)` from `0` to `1`: the point that stays put when a limit stops it, and that `rotate` turns around. | | `rotate` | `0` | Degrees clockwise. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#anchor) ##### `pz.anchors.place` ```python place( rect, anchor, design, actual, *, min_size=(0, 0), max_size=(0, 0), pivot=(0.5, 0.5), ) ``` Where a box designed in a parent of size `design` goes in a parent of size `actual`, following its anchor, with size limits and a pivot. The math behind `pz.anchor_layout` and designed forms. | Property | Default | Description | | --- | --- | --- | | `rect` | *required* | `(x, y, width, height)` in the design size. | | `anchor` | *required* | A preset, words or edges. | | `design` | *required* | The parent's design size. | | `actual` | *required* | The parent's current size. | | `min_size` | `(0, 0)` | `(width, height)` lower limits (`0`: none). | | `max_size` | `(0, 0)` | `(width, height)` upper limits (`0`: none). | | `pivot` | `(0.5, 0.5)` | The point that stays put when a limit stops the box from stretching. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#place) #### Related - [Stack](https://albakore.github.io/pyzed/library/stack/): Layers children on top of each other; `pin` places one at x, y. - [Grid](https://albakore.github.io/pyzed/library/grid/): Equal columns, or CSS-like tracks with spans. - [Container](https://albakore.github.io/pyzed/library/container/): Size, padding, alignment, background, border and shadow for one child. ### Animation > Presets, keyframes and transitions for any widget. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/animation/ :::tip[In plain words] Makes things move: fade in, slide, bounce or glow, without extra work. ::: Every widget has `animate()` and `transition()`. `animate` plays one of 47 presets or a `pz.Animation` when the widget appears, on hover, press, focus, click or while `active`; `transition` animates property changes like CSS. `pz.stagger` cascades a list in and `pz.presence` animates content in and out when it changes. Everything runs natively, without calling Python per frame. See the [Animation guide](https://albakore.github.io/pyzed/animation/). `pz.Animation` · Category: [Content](https://albakore.github.io/pyzed/library/#content) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#animation-1) **Code:** ```python pz.column(pz.stagger([ ui.card(ui.label(name), width=320).animate("lift", on="hover") for name in ("fade_in_up", "lift on hover", "stagger") ], "fade_in_up", step=60), spacing=10) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - To show that something appeared, changed or needs attention: a toast, a new row, an error shake. - For hover and press feedback on cards and custom buttons. - For page and tab transitions with `pz.presence`. #### Usage ```python import pyzed as pz from pyzed import ui class Inbox(pz.App): errors = 0 page = 0 def view(self): return pz.column([ ui.input(self.query, self.search).animate("shake", key=self.errors), pz.presence(self.page_view(), key=self.page, enter="fade_in_right", exit="fade_out"), ui.button("Record", self.record).animate("glow_pulse", active=self.recording), ], spacing=12) ``` #### Events Animation has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Tips :::tip Screenshots and `pz.set_reduced_motion(True)` show every animation at rest, so tests are stable. Respect users who turn motion off. ::: #### Properties and API ##### `pz.Animation` ```python @dataclass class Animation(keyframes=(), duration=300, delay=0, easing='ease', repeat=1, direction='normal', fill='both', on='mount', category='custom', description='', _frames=()) ``` A keyframe animation, like a CSS `@keyframes` rule with its timing. [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#animation-1) ##### `pz.stagger` ```python stagger(items, animation='fade_in_up', *, step=40, delay=0, **options) ``` `items` with the same animation, each starting `step` milliseconds after the previous one (a list that cascades in):: [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#stagger) ##### `pz.presence` ```python presence( content, key, *, enter='fade_in', exit='fade_out', id=None, duration=None, easing=None, ) ``` Shows `content` and, when `key` changes, animates the old content out (`exit`) while the new one comes in (`enter`), like page transitions:: [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#presence) ##### `pz.define_animation` ```python define_animation(name, animation=None, **options) ``` Names an animation so `animate(name)` plays it; returns it. [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#define_animation) ##### `pz.set_reduced_motion` ```python set_reduced_motion(on=True) ``` Turns motion off (`True`) or back on: animations show their resting state at once. [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#set_reduced_motion) #### Related - [Effects](https://albakore.github.io/pyzed/library/effects/): Glow, bloom, glass and opacity as style properties. - [Card](https://albakore.github.io/pyzed/library/card/): A bordered surface with an optional title and actions. - [Toast](https://albakore.github.io/pyzed/library/toast/): Notifications stacked in the bottom-right corner. ### Avatar > A round avatar with initials in a collaborator color. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/avatar/ :::tip[In plain words] A circle with someone's initials, in their own color. ::: A circle with initials. `index` picks one of the theme's collaborator (player) colors, so the same person keeps the same color; `color` sets it directly. `ui.avatar` · Category: [Display](https://albakore.github.io/pyzed/library/#display) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#avatar) **Code:** ```python pz.row([ ui.avatar("AL", index=0), ui.avatar("KV", index=1), ui.avatar("MZ", index=2, size=28), ui.avatar("JD", index=3, size=36), ], spacing=8, align="center") ``` #### When to use - For the account in the title bar, comment authors or collaborators. - For several people at once use [Facepile](https://albakore.github.io/pyzed/library/facepile/). #### Usage ```python import pyzed as pz from pyzed import ui pz.row([ ui.avatar("AL", index=0), ui.avatar("KV", index=1), ui.avatar("MZ", index=2, size=28), ui.avatar("JD", index=3, size=36), ], spacing=8, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Collaborator color ```python ui.avatar("AL", index=0) ``` ```python ui.avatar("KV", index=1) ``` ```python ui.avatar("MZ", index=2) ``` ```python ui.avatar("JD", index=3) ``` ```python ui.avatar("SR", index=4) ``` ```python ui.avatar("PB", index=5) ``` ##### Size ```python ui.avatar("KV", size=18) ``` ```python ui.avatar("KV", size=22) ``` ```python ui.avatar("KV", size=32) ``` ```python ui.avatar("KV", size=48) ``` ##### Color ```python ui.avatar("PZ", color="#c678dd", size=32) ``` ```python ui.avatar("UI", color="#e5c07b", size=32) ``` ##### States and events `image=` shows a picture instead of the initials and `tooltip=` names the person on hover. ```python ui.avatar("KK", status="online", size=32) ``` ```python ui.avatar("AL", status="away", index=2, size=32) ``` ```python ui.avatar("MZ", status="busy", index=4, size=32) ``` #### Events Avatar has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.avatar` ```python avatar( initials, *, color=None, size=22, index=0, image=None, status=None, tooltip=None, theme=None, ) ``` A round avatar with initials. | Property | Default | Description | | --- | --- | --- | | `initials` | *required* | Initials (the first two are used). | | `color` | `None` | Background color. | | `size` | `22` | Diameter. | | `index` | `0` | Picks a collaborator color from the theme (`theme.players`). | | `image` | `None` | A picture (path or bytes) instead of the initials. | | `status` | `None` | Presence dot: `"online"`, `"away"`, `"busy"`, `"offline"` or a color. | | `tooltip` | `None` | Text shown on hover (the person's name). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#avatar) #### Related - [Facepile](https://albakore.github.io/pyzed/library/facepile/): Overlapping collaborator avatars with +N. - [Title bar](https://albakore.github.io/pyzed/library/title-bar/): The top bar with project and branch pickers. ### Badge > A small pill for statuses, versions and counters. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/badge/ :::tip[In plain words] A tiny colored pill with a word or two, like “beta” or “3 errors”. ::: A small pill with text and an optional icon. `tint` picks a semantic color and `variant` is `"soft"` (default), `"solid"` or `"outline"`. `ui.badge` · Category: [Display](https://albakore.github.io/pyzed/library/#display) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#badge) **Code:** ```python pz.row([ ui.badge("accent"), ui.badge("success", tint="success"), ui.badge("warning", tint="warning"), ui.badge("error", tint="error", icon="circle-x"), ], spacing=8) ``` #### When to use - For short read-only statuses: `beta`, `M` (modified), `v0.4`, `3 errors`. - For a round number on top of an icon use [Count badge](https://albakore.github.io/pyzed/library/count-badge/). #### Usage ```python import pyzed as pz from pyzed import ui pz.row([ ui.badge("accent"), ui.badge("success", tint="success"), ui.badge("warning", tint="warning"), ui.badge("error", tint="error", icon="circle-x"), ], spacing=8) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Tint ```python ui.badge("accent") ``` ```python ui.badge("passed", tint="success") ``` ```python ui.badge("pending", tint="warning") ``` ```python ui.badge("failed", tint="error") ``` ```python ui.badge("info", tint="info") ``` ```python ui.badge("custom", tint="#c678dd") ``` ##### Variant ```python ui.badge("soft") ``` ```python ui.badge("solid", variant="solid") ``` ```python ui.badge("outline", variant="outline") ``` ##### With an icon ```python ui.badge("new", icon="sparkles") ``` ```python ui.badge("3 errors", tint="error", icon="circle-x") ``` ```python ui.badge("verified", tint="success", variant="solid", icon="check") ``` ##### States and events ```python ui.badge("beta", size="sm") ``` ```python ui.badge("Pro", size="lg", icon="star") ``` ```python ui.badge("3 issues", tint="warning", on_press=on_press) ``` #### Events Badge has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `()` | Makes it clickable. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Inbox(pz.App): def __init__(self): self.unread = 3 def view(self): return ui.badge(f"{self.unread} new", tint="accent", on_press=lambda: setattr(self, "unread", 0)) # on_press makes it clickable ``` **Declarative:** ```python class Inbox(pz.App): unread = 3 def update(self, message): if message == "read all": self.unread = 0 def view(self): return ui.badge(f"{self.unread} new", on_press="read all") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: unread: int = 3 def view(state, set_state): return ui.badge(f"{state.unread} new", on_press=lambda: set_state(unread=0)) ``` #### Properties and API ##### `ui.badge` ```python badge( content, *, tint='accent', variant='soft', icon=None, size='md', on_press=None, theme=None, ) ``` A small pill for statuses and counters. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `tint` | `"accent"` | Semantic color: `"accent"`, `"error"`, `"warning"`, `"success"`, `"info"` or a token. | | `variant` | `"soft"` | `"soft"`, `"solid"` or `"outline"`. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `size` | `"md"` | `"sm"`, `"md"` or `"lg"`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#badge) #### Related - [Count badge](https://albakore.github.io/pyzed/library/count-badge/): A round counter that shows 99+ above its max. - [Indicator](https://albakore.github.io/pyzed/library/indicator/): A colored dot for status, presence or unsaved changes. - [Chip](https://albakore.github.io/pyzed/library/chip/): A compact tag: clickable as a filter, removable with an ✕. ### Bar chart > A vertical bar chart with labels. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/bar-chart/ :::tip[In plain words] A chart of bars to compare a few amounts. ::: A vertical bar chart drawn with `pz.canvas` in the theme colors, with optional labels under the bars. `ui.bar_chart` · Category: [Data](https://albakore.github.io/pyzed/library/#data) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#bar_chart) **Code:** ```python ui.bar_chart([12, 19, 8, 15, 22, 17, 9], labels=["M", "T", "W", "T", "F", "S", "S"], width=360, height=180) ``` #### When to use - To compare a handful of values side by side (per day, per category). #### Usage ```python from pyzed import ui ui.bar_chart([12, 19, 8, 15, 22, 17, 9], labels=["M", "T", "W", "T", "F", "S", "S"], width=360, height=180) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python ui.bar_chart([12, 19, 8, 15, 22], labels=["M", "T", "W", "T", "F"], width=240, height=120) ``` ```python ui.bar_chart([4, 8, 6, 9, 3, 7, 5, 10], width=240, height=100) ``` ```python ui.bar_chart([5, 9, 7, 12], labels=["Q1", "Q2", "Q3", "Q4"], width=240, height=120, tint="success") ``` ```python ui.bar_chart([30, 12, 18], labels=["cpu", "io", "net"], width=240, height=120, tint="warning") ``` #### Events Bar chart has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.bar_chart` ```python bar_chart(values, *, labels=None, width=320, height=160, tint='accent', theme=None) ``` A vertical bar chart with optional labels. | Property | Default | Description | | --- | --- | --- | | `values` | *required* | Values. | | `labels` | `None` | Labels under each bar. | | `width` | `320` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `160` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `tint` | `"accent"` | Semantic color: `"accent"`, `"error"`, `"warning"`, `"success"`, `"info"` or a token. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#bar_chart) #### Related - [Donut](https://albakore.github.io/pyzed/library/donut/): A donut chart with a label in the middle. - [Sparkline](https://albakore.github.io/pyzed/library/sparkline/): A tiny line chart for trends. - [Stat](https://albakore.github.io/pyzed/library/stat/): A dashboard number with change and sparkline. ### Breadcrumbs > `src › main.rs › fn main`, optionally clickable. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/breadcrumbs/ :::tip[In plain words] Shows where you are, step by step: Folder › Subfolder › File. ::: The path to the current location. Parts are strings or `(icon, text)` tuples; `on_press` receives the index of the clicked part. `ui.breadcrumbs` · Category: [Navigation](https://albakore.github.io/pyzed/library/#navigation) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#breadcrumbs) **Code:** ```python pz.column([ ui.breadcrumbs(["src", "ui", "button.rs"]), ui.breadcrumbs([("folder", "src"), ("file-code", "main.rs"), "fn main"], on_press=on_press), ui.breadcrumbs(["Settings", "Editor", "Font"], separator="/"), ], spacing=14) ``` #### When to use - Above an editor or a nested view, to show where you are and jump to a parent. #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ ui.breadcrumbs(["src", "ui", "button.rs"]), ui.breadcrumbs([("folder", "src"), ("file-code", "main.rs"), "fn main"], on_press=on_press), ui.breadcrumbs(["Settings", "Editor", "Font"], separator="/"), ], spacing=14) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python ui.breadcrumbs(["src", "ui", "button.rs"]) ``` ```python ui.breadcrumbs([("folder", "src"), ("file-code", "main.rs"), "fn main"]) ``` ```python ui.breadcrumbs(["Settings", "Editor", "Font"], separator="/") ``` ```python ui.breadcrumbs(["Home", "Projects", "pyzed"], on_press=on_press) ``` ##### States and events ```python ui.breadcrumbs(["pyzed", "python", "pyzed", "ui", "lists.py"], max_items=3, on_press=on_press, on_more=on_more) ``` #### Events Breadcrumbs has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `(index)` | Called with the index of the clicked part. | | `on_more` | `()` | Makes the `…` clickable. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Browser(pz.App): def __init__(self): self.path = ["home", "ada", "projects", "pyzed"] def go(self, index): # on_press: the index of the clicked part self.path = self.path[:index + 1] def view(self): return ui.breadcrumbs(self.path, on_press=self.go, max_items=3, on_more=lambda: self.go(0)) # the … of the hidden parts ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class GoTo: index: int class Browser(pz.App): path = ["home", "ada", "projects", "pyzed"] def update(self, message): match message: case GoTo(index): self.path = self.path[:index + 1] def view(self): return ui.breadcrumbs(self.path, on_press=GoTo) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: path: tuple = ("home", "ada", "projects", "pyzed") def view(state, set_state): return ui.breadcrumbs(list(state.path), on_press=lambda i: set_state(path=state.path[:i + 1])) ``` #### Properties and API ##### `ui.breadcrumbs` ```python breadcrumbs( parts, *, separator='›', on_press=None, max_items=None, on_more=None, theme=None, ) ``` `src › main.rs › fn main`. Parts can be strings or `(icon, text)` tuples. | Property | Default | Description | | --- | --- | --- | | `parts` | *required* | The parts. | | `separator` | `"›"` | Separator. | | `max_items` | `None` | Keeps the first part and the last ones and shows `…` for the rest. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_press`, `on_more` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#breadcrumbs) #### Related - [Toolbar](https://albakore.github.io/pyzed/library/toolbar/): The bar under the tabs: breadcrumbs and buffer actions. - [Tab bar](https://albakore.github.io/pyzed/library/tab-bar/): Editor tabs with icons, dirty dots and close buttons. ### Button > The themed button: variants, sizes, icons and shortcuts. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/button/ :::tip[In plain words] A button is something you click to make the app do something: save, send, open, delete. ::: Displays a themed button. It reads its colors from the current theme, can carry an icon and a keyboard shortcut, and comes in several variants and sizes. Any style parameter of `pz.button` (`bg`, `hover_bg`, `color`, `shadow`, `radius`…) overrides the theme's. `ui.button` · Category: [Actions](https://albakore.github.io/pyzed/library/#actions) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#button) **Code:** ```python pz.row([ ui.button("Cancel", on_cancel, variant="ghost"), ui.button("Save", on_save, icon="save", variant="solid", keys="ctrl-s"), ], spacing=8) ``` #### When to use - For the main actions of a form, dialog or toolbar. - Use `variant="solid"` for the one primary action and `"ghost"` for secondary ones. - For a button with only an icon, use [Icon button](https://albakore.github.io/pyzed/library/icon-button/). #### Usage ```python import pyzed as pz from pyzed import ui class Editor(pz.App): def save(self): ... def view(self): return ui.button("Save", self.save, icon="save", keys="ctrl-s") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Variant `filled` is the default; use `solid` for the one main action of a screen. ```python ui.button("Filled", on_press) ``` ```python ui.button("Ghost", on_press, variant="ghost") ``` ```python ui.button("Subtle", on_press, variant="subtle") ``` ```python ui.button("Outline", on_press, variant="outline") ``` ```python ui.button("Solid", on_press, variant="solid") ``` ```python ui.button("Tinted", on_press, variant="tinted") ``` ##### Semantic colors A color name as `variant` gives a tinted button; `tint=` colors a `solid` one. ```python ui.button("Upgrade", on_press, variant="accent", icon="sparkles") ``` ```python ui.button("Done", on_press, variant="success", icon="check") ``` ```python ui.button("Careful", on_press, variant="warning", icon="triangle-alert") ``` ```python ui.button("Delete", on_press, variant="error", icon="trash-2") ``` ```python ui.button("Details", on_press, variant="info", icon="info") ``` ```python ui.button("Delete forever", on_press, variant="solid", tint="error") ``` ##### Size ```python ui.button("Extra small", on_press, size="xs") ``` ```python ui.button("Small", on_press, size="sm") ``` ```python ui.button("Medium", on_press, size="md") ``` ```python ui.button("Large", on_press, size="lg") ``` ##### Content ```python ui.button("Save", on_press, icon="save") ``` ```python ui.button("Next", on_press, icon="arrow-right", icon_position="end") ``` ```python ui.button("Save", on_press, icon="save", keys="ctrl-s") ``` ```python ui.button("Online", on_press, icon="circle", icon_color="success") ``` ```python ui.button(icon="plus", on_press=on_press) ``` ##### State A button without `on_press` is drawn disabled, so unfinished actions look unfinished. ```python ui.button("Selected", on_press, selected=True) ``` ```python ui.button("Disabled", on_press, disabled=True) ``` ```python ui.button("Not wired yet") ``` ```python pz.container(ui.button("Sign in", on_press, variant="solid", full_width=True), width=280) ``` ##### Style overrides The style arguments of `pz.button` (`bg`, `hover_bg`, `pressed_bg`, `color`, `border_color`, `shadow`, `radius`, `padding`) replace the theme's values for that button only. ```python ui.button("Lifted", on_press, variant="solid", shadow=("#00000066", (0, 4), 12)) ``` ```python ui.button("Custom", on_press, bg="#c678dd", hover_bg="#d08ae6", color="#ffffff") ``` ```python ui.button("Gold border", on_press, variant="outline", border_color="#e5c07b") ``` ```python ui.button("Pill", on_press, variant="solid", radius=999) ``` ##### States and events ```python ui.button("Saving", on_press, icon="save", loading=True) ``` ```python ui.button("Save", on_press, tooltip="Writes the file") ``` ##### Base widget The `pz.*` widget underneath: no theme, every color and size is yours. ```python pz.button("pz.button", on_press, padding=(6, 14), bg="#3a7bc8", color="#ffffff", radius=6) ``` ```python pz.button(pz.row([pz.icon("heart", size=14), pz.text("Like")], spacing=6, align="center"), on_press, padding=(6, 12), bg="#c678dd22", color="#c678dd", border_color="#c678dd", border_width=1, radius=999) ``` #### Examples ##### Full width `full_width=True` stretches the button to its container. **Code:** ```python pz.column([ ui.button("Sign in", on_press, variant="solid", full_width=True), ui.button("Create an account", on_press, variant="outline", full_width=True), ], spacing=8, width=320) ``` #### Events Button has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_press` | `ui.button`, `pz.button` | `()` | Message or callable sent on press. `None` disables the control. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Editor(pz.App): def __init__(self): self.saved = 0 def save(self): # on_press: called with nothing self.saved += 1 def view(self): return pz.row([ ui.button("Save", self.save, icon="save", variant="solid", keys="ctrl-s"), ui.button("Reset", lambda: setattr(self, "saved", 0), variant="ghost"), ui.label(f"Saved {self.saved} times"), ], spacing=8, align="center") ``` **Declarative:** ```python class Editor(pz.App): saved = 0 def update(self, message): # every button sends a message here match message: case "save": self.saved += 1 case "reset": self.saved = 0 def view(self): return pz.row([ ui.button("Save", "save", icon="save", variant="solid", keys="ctrl-s"), ui.button("Reset", "reset", variant="ghost"), ui.label(f"Saved {self.saved} times"), ], spacing=8, align="center") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: saved: int = 0 def view(state, set_state): # a pure function: state in, widgets out return pz.row([ ui.button("Save", lambda: set_state(saved=state.saved + 1), icon="save", variant="solid"), ui.button("Reset", lambda: set_state(saved=0), variant="ghost"), ui.label(f"Saved {state.saved} times"), ], spacing=8, align="center") ``` #### Tips :::tip To pass a value to the callback, bind it with a default argument: `ui.button(name, lambda n=name: self.open(n))`. ::: #### Properties and API ##### `ui.button` ```python button( content=None, on_press=None, *, icon=None, icon_position='start', icon_color=None, variant='filled', tint=None, size='md', selected=False, disabled=False, full_width=False, keys=None, loading=False, tooltip=None, theme=None, **style, ) ``` A themed button with variants, sizes, an icon and a shortcut. | Property | Default | Description | | --- | --- | --- | | `content` | `None` | Text or widget. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `icon_position` | `"start"` | `"start"` or `"end"`. | | `icon_color` | `None` | Icon color: a theme token or a hex color. | | `variant` | `"filled"` | `"filled"`, `"ghost"`, `"subtle"`, `"outline"`, `"solid"`, `"tinted"`, or a semantic color: `"accent"`, `"error"`, `"warning"`, `"success"`, `"info"`. | | `tint` | `None` | Color for the `solid` and `tinted` variants. | | `size` | `"md"` | `"xs"`, `"sm"`, `"md"` or `"lg"`. | | `selected` | `False` | Marks it as selected. | | `disabled` | `False` | Disables it (ignores clicks). | | `full_width` | `False` | Fills the full width. | | `keys` | `None` | Shortcut shown at the end, written as a string: `"ctrl-s"`, `"cmd-k cmd-s"`. | | `loading` | `False` | Shows a spinner in place of the icon and ignores presses (keep a `pz.every(1/30, ...)` subscription while it spins). | | `tooltip` | `None` | Text shown on hover. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | | `**style` | — | Any `pyzed.button` style parameter (`bg`, `hover_bg`, `color`…). | Events: `on_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#button) ##### `pz.button` ```python button( content, on_press=None, *, padding=None, width=None, height=None, bg=None, color=None, border_color=None, border_width=0.0, radius=None, shadow=None, hover_bg=None, hover_color=None, hover_border_color=None, pressed_bg=None, disabled_color=None, clip=False, ) ``` A button with no predefined style. For the themed button use `ui.button`. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Button content. | | `padding` | `None` | Inner padding: `8`, `(vertical, horizontal)` or `(top, right, bottom, left)`. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `color` | `None` | Text or icon color. | | `border_color` | `None` | Border color. | | `border_width` | `0.0` | Border width in pixels. | | `radius` | `None` | Corner radius: a number or `(top_left, top_right, bottom_right, bottom_left)`. | | `shadow` | `None` | Shadow: `(color, (dx, dy), blur)`. | | `hover_bg` | `None` | Background on hover. | | `hover_color` | `None` | Text color on hover. | | `hover_border_color` | `None` | Border color on hover. | | `pressed_bg` | `None` | Background while pressed. | | `disabled_color` | `None` | Text color when disabled. | | `clip` | `False` | Clips content that overflows the bounds. | Events: `on_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#button) #### Related - [Icon button](https://albakore.github.io/pyzed/library/icon-button/): A square button with just an icon and an optional tooltip. - [Split button](https://albakore.github.io/pyzed/library/split-button/): A main action plus an arrow that opens more options. - [Toggle group](https://albakore.github.io/pyzed/library/toggle-group/): An icon-only segmented control. - [Tooltip](https://albakore.github.io/pyzed/library/tooltip/): A hint shown on hover, optionally with its shortcut. ### Calendar > A month grid to pick a day, a range or several days, always on screen. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/calendar/ :::tip[In plain words] A month on screen, like a wall calendar, where you click days to choose them. ::: `ui.Calendar` shows one or more months. `mode` picks a single day (`"single"`), a range (`"range"`, two clicks) or any number of days (`"multiple"`, each click toggles one). The header switches to a grid of months and then of years to jump far, and the arrows of the keyboard move the focused day (Page Up/Page Down by month, Enter picks). The pickers on this page open one of these in a popup. `ui.Calendar` · Category: [Dates and times](https://albakore.github.io/pyzed/library/#dates-and-times) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#calendar) **Code:** ```python pz.row([ ui.Calendar(value="2026-10-22", today_button=True, on_change=on_change), ui.Calendar(value=("2026-10-05", "2026-10-14"), mode="range", disabled=["weekend"], on_change=on_change), ], spacing=24) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - In a side panel or a dashboard, where the calendar stays visible. - `first_weekday` (`"monday"`, `"sunday"`...) and `week_numbers=True` follow local customs. - Inside a form field, use [Date picker](https://albakore.github.io/pyzed/library/date-picker/) instead. #### Usage ```python import pyzed as pz from pyzed import ui class Planner(pz.App): def __init__(self): self.days = [] def view(self): return pz.row([ ui.Calendar(value=self.days, mode="multiple", week_numbers=True, on_change=lambda e: setattr(self, "days", e.value)), pz.column([ui.label(ui.format_date(d, "ddd D MMM")) for d in self.days], spacing=4), ], spacing=16) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Mode ```python ui.Calendar(value="2026-10-22", on_change=on_change) ``` ```python ui.Calendar(value=("2026-10-05", "2026-10-14"), mode="range", on_change=on_change) ``` ```python ui.Calendar(value=["2026-10-06", "2026-10-13", "2026-10-20", "2026-10-27"], mode="multiple", on_change=on_change) ``` ##### Options ```python ui.Calendar(value="2026-10-22", week_numbers=True, first_weekday="monday", on_change=on_change) ``` ```python ui.Calendar(value="2026-10-22", first_weekday="sunday", on_change=on_change) ``` ```python ui.Calendar(value="2026-10-22", min="2026-10-08", max="2026-10-28", disabled=["weekend"], on_change=on_change) ``` ```python ui.Calendar(value="2026-10-22", show_outside=False, today_button=True, on_change=on_change) ``` ##### Views A click on the title goes to the months, and another one to the years. ```python ui.Calendar(value=("2026-10-26", "2026-11-04"), mode="range", months=2, on_change=on_change) ``` ```python ui.Calendar(value="2026-10-22", on_change=on_change) ``` ```python ui.Calendar(value="2026-10-22", on_change=on_change) ``` #### Events Calendar has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Handler gets | When | | --- | --- | --- | | `on_change` | `(event)` | Receives `event.value` (a date, a tuple or a list). | | `on_month` | `(event)` | Receives `event.value`, the `(year, month)` shown. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Planner(pz.App): def __init__(self): self.days = [] def changed(self, event): # on_change: the list of days ("multiple" mode) self.days = event.value def view(self): return pz.row([ ui.Calendar(value=self.days, mode="multiple", on_change=self.changed), ui.label(f"{len(self.days)} days"), ], spacing=16) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Day: value: object class Planner(pz.App): day = None def update(self, message): match message: case Day(value): self.day = value def view(self): return ui.Calendar(value=self.day, today_button=True, on_change=lambda e: Day(e.value)) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: stay: tuple = ("2026-10-05", "2026-10-09") def view(state, set_state): return ui.Calendar(value=state.stay, mode="range", months=2, on_change=lambda e: set_state(stay=e.value)) ``` #### Properties and API ##### `ui.Calendar` ```python class Calendar ``` A component with a month to pick a day on (`mode="single"`), a range (`"range"`: the first click starts it, the second ends it) or several days (`"multiple"`). The title opens a grid of months, then of years. Once clicked it takes the keyboard: arrows move, Enter picks, Page Up/Down change month. See the [Calendar](https://albakore.github.io/pyzed/library/calendar/) page. | Property | Default | Description | | --- | --- | --- | | `value` | `None` | A date (`datetime.date` or `"2026-10-22"`), a `(start, end)` pair or a list of dates, by `mode`. | | `mode` | `"single"` | `"single"`, `"range"` or `"multiple"`. | | `min` | `None` | The earliest day that can be picked. | | `max` | `None` | The latest day that can be picked. | | `disabled` | `()` | Days that cannot be picked: dates, weekday names (`"sunday"`) or `"weekends"`. | | `first_weekday` | `"monday"` | `"monday"`, `"sunday"` or `"saturday"`. | | `months` | `1` | Months shown side by side. | | `week_numbers` | `False` | Shows the ISO week number of each row. | | `show_outside` | `True` | Shows the days of the months around. | | `today_button` | `False` | Adds a Today link. | Events: `on_change`, `on_month` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#calendar) #### Related - [Date picker](https://albakore.github.io/pyzed/library/date-picker/): A date field with a calendar that drops down, in the format you choose. - [Date range picker](https://albakore.github.io/pyzed/library/date-range-picker/): Two dates in one field, with two months side by side and quick ranges. ### Callout > An inline notice with a title, text and actions. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/callout/ :::tip[In plain words] A colored box inside the page with a message: a tip, a warning or an error. ::: An inline notice (a callout or banner): an icon, a title, an optional description, action buttons and a close button with `on_dismiss`. `tint` is `"info"` (default), `"success"`, `"warning"`, `"error"` or any theme token. `ui.callout` · Category: [Feedback](https://albakore.github.io/pyzed/library/#feedback) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#callout) **Code:** ```python pz.column([ ui.callout("A new version is out", "Pyzed 0.4 adds the component designer.", tint="info", actions=[ui.button("What's new", on_open, size="sm")], on_dismiss=on_dismiss), ui.callout("Could not save", "The file is read-only.", tint="error"), ], spacing=10, width=520) ``` #### When to use - For messages that belong to a place in the UI: a read-only file, a new version, a failed sync. - For short-lived messages, use a [Toast](https://albakore.github.io/pyzed/library/toast/). #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ ui.callout("A new version is out", "Pyzed 0.4 adds the component designer.", tint="info", actions=[ui.button("What's new", on_open, size="sm")], on_dismiss=on_dismiss), ui.callout("Could not save", "The file is read-only.", tint="error"), ], spacing=10, width=520) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Tint Each tint picks a matching icon; `icon=` chooses another. ```python pz.container(ui.callout("Heads up", "Pyzed 0.5 is out."), width=380) ``` ```python pz.container(ui.callout("Synced", "All changes are saved.", tint="success"), width=380) ``` ```python pz.container(ui.callout("Unsaved changes", "Save before closing.", tint="warning"), width=380) ``` ```python pz.container(ui.callout("Could not save", "The file is read-only.", tint="error"), width=380) ``` ```python pz.container(ui.callout("Tip", "Ctrl+Shift+P opens the palette.", tint="accent", icon="lightbulb"), width=380) ``` ##### Content ```python pz.container(ui.callout("Read-only file"), width=380) ``` ```python pz.container(ui.callout("A new version is out", "Restart to update.", actions=[ui.button("Restart", on_restart, size="sm")]), width=380) ``` ```python pz.container(ui.callout("Welcome!", "Open a folder to start.", on_dismiss=on_dismiss), width=380) ``` #### Events Callout has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_dismiss` | `()` | Adds a close button. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Updates(pz.App): def __init__(self): self.visible = True def view(self): if not self.visible: return ui.muted("No news.") return ui.callout("A new version is out", "Pyzed adds the component designer.", tint="info", on_dismiss=lambda: setattr(self, "visible", False)) # adds the ✕ ``` **Declarative:** ```python class Updates(pz.App): visible = True def update(self, message): if message == "dismiss": self.visible = False def view(self): return ui.callout("A new version is out", tint="info", on_dismiss="dismiss") if self.visible \ else ui.muted("No news.") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: visible: bool = True def view(state, set_state): if not state.visible: return ui.muted("No news.") return ui.callout("A new version is out", tint="info", on_dismiss=lambda: set_state(visible=False)) ``` #### Properties and API ##### `ui.callout` ```python callout( title, description=None, *, tint='info', icon=None, actions=(), on_dismiss=None, theme=None, ) ``` An inline notice (a callout or banner). | Property | Default | Description | | --- | --- | --- | | `title` | *required* | Title (text or widget). | | `description` | `None` | Secondary text. | | `tint` | `"info"` | `"info"`, `"success"`, `"warning"`, `"error"` or `"hint"`: picks the color and icon. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `actions` | `()` | Extra widgets (usually buttons) shown as actions. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_dismiss` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#callout) #### Related - [Toast](https://albakore.github.io/pyzed/library/toast/): Notifications stacked in the bottom-right corner. - [Alert](https://albakore.github.io/pyzed/library/alert/): A message with one button. - [Empty state](https://albakore.github.io/pyzed/library/empty-state/): A centered placeholder for empty lists and searches. ### Canvas > 2D drawing with shapes, paths, text and mouse events. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/canvas/ :::tip[In plain words] A blank sheet to draw shapes, lines and text on, for charts and games. ::: A 2D drawing surface. `shapes` is a list made with [`pyzed.draw`](https://albakore.github.io/pyzed/reference/draw/) (rectangles, circles, arcs, paths, text, images…). Mouse callbacks receive coordinates relative to the canvas; with an `id` the geometry is cached between frames. The charts of this library are drawn with it. `pz.canvas` · Category: [Content](https://albakore.github.io/pyzed/library/#content) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#canvas) **Code:** ```python pz.canvas([ draw.rect(10, 10, 120, 80, fill="#74ade8", radius=8), draw.circle(200, 50, 40, fill="#a1c181"), draw.arc(300, 50, 40, 0, 270, stroke="#e5c07b", width=8, cap="round"), draw.polygon([(360, 90), (400, 10), (440, 90)], fill="#d07277"), draw.line(10, 120, 440, 120, stroke="#5d636f", width=2, dash=[6, 4]), draw.text(225, 150, "pz.canvas + pyzed.draw", color="#a9afbc", size=16, align_x="center"), ], width=450, height=170) ``` #### When to use - For charts, games, diagrams, drawing apps and custom widgets. #### Usage ```python import pyzed as pz from pyzed import draw pz.canvas([ draw.rect(10, 10, 120, 80, fill="#74ade8", radius=8), draw.circle(200, 50, 40, fill="#a1c181"), draw.arc(300, 50, 40, 0, 270, stroke="#e5c07b", width=8, cap="round"), draw.polygon([(360, 90), (400, 10), (440, 90)], fill="#d07277"), draw.line(10, 120, 440, 120, stroke="#5d636f", width=2, dash=[6, 4]), draw.text(225, 150, "pz.canvas + pyzed.draw", color="#a9afbc", size=16, align_x="center"), ], width=450, height=170) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Shapes ```python pz.canvas([draw.rect(10, 10, 140, 70, fill="#74ade8", radius=10)], width=160, height=90) ``` ```python pz.canvas([draw.circle(50, 45, 36, fill="#a1c181")], width=100, height=90) ``` ```python pz.canvas([draw.arc(50, 45, 34, 0, 270, stroke="#e5c07b", width=8, cap="round")], width=100, height=90) ``` ```python pz.canvas([draw.polygon([(10, 80), (50, 10), (90, 80)], fill="#d07277")], width=100, height=90) ``` ```python pz.canvas([draw.line(10, 45, 190, 45, stroke="#c678dd", width=3, dash=[8, 5])], width=200, height=90) ``` ```python pz.canvas([draw.text(100, 45, "pyzed.draw", color="#74ade8", size=20, align_x="center", align_y="center")], width=200, height=90) ``` #### Events Canvas has **5 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `(x, y)` | Callable that receives `(x, y)` on press. | | `on_release` | `(x, y)` | Callable that receives `(x, y)` on release. | | `on_right_press` | `(x, y)` | Callable that receives `(x, y)` on right click. | | `on_move` | `(x, y)` | Called with `(x, y)` when the mouse moves. | | `on_scroll` | `(dx, dy)` | Callable that receives `(dx, dy)` in lines when the wheel is used. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Paint(pz.App): def __init__(self): self.dots, self.drawing = [], False def press(self, x, y): # on_press / on_move get the position self.drawing = True self.dots.append((x, y)) def move(self, x, y): if self.drawing: self.dots.append((x, y)) def view(self): return pz.canvas([draw.circle(x, y, 3, fill="#74ade8") for x, y in self.dots], width=420, height=200, cursor="crosshair", on_press=self.press, on_move=self.move, on_release=lambda x, y: setattr(self, "drawing", False), on_right_press=lambda x, y: self.dots.clear()) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Dot: x: float y: float class Paint(pz.App): dots = [] def update(self, message): match message: case Dot(x, y): self.dots = self.dots + [(x, y)] case "clear": self.dots = [] def view(self): return pz.canvas([draw.circle(x, y, 3, fill="#74ade8") for x, y in self.dots], width=420, height=200, on_press=Dot, on_right_press=lambda x, y: "clear") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: dots: tuple = () zoom: float = 1.0 def view(state, set_state): shapes = [draw.circle(x, y, 3 * state.zoom, fill="#74ade8") for x, y in state.dots] return pz.canvas(shapes, width=420, height=200, on_press=lambda x, y: set_state(dots=state.dots + ((x, y),)), on_scroll=lambda dx, dy: set_state(zoom=max(0.5, state.zoom + dy * 0.1))) ``` #### Properties and API ##### `pz.canvas` ```python canvas( shapes=None, *, width=None, height=None, id=None, on_press=None, on_release=None, on_right_press=None, on_move=None, on_scroll=None, cursor=None, ) ``` A 2D drawing surface. `shapes` is a list created with [`pyzed.draw`](https://albakore.github.io/pyzed/reference/draw/). Mouse callbacks receive coordinates relative to the canvas. With an `id`, the geometry is cached between frames and only recomputed when the shapes change. See the [drawing with canvas](https://albakore.github.io/pyzed/guides/canvas/) guide. | Property | Default | Description | | --- | --- | --- | | `shapes` | `None` | List of `pyzed.draw` shapes (nested lists are accepted). | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `id` | `None` | Enables the geometry cache. | | `cursor` | `None` | Mouse cursor (`"crosshair"`, `"pointer"`…). | Events: `on_press`, `on_release`, `on_right_press`, `on_move`, `on_scroll` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#canvas) #### Related - [Bar chart](https://albakore.github.io/pyzed/library/bar-chart/): A vertical bar chart with labels. - [Donut](https://albakore.github.io/pyzed/library/donut/): A donut chart with a label in the middle. - [Stack](https://albakore.github.io/pyzed/library/stack/): Layers children on top of each other; `pin` places one at x, y. ### Card > A bordered surface with an optional title and actions. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/card/ :::tip[In plain words] A box with a border that keeps related things together, like a card on a table. ::: A rounded, bordered surface that groups content. `title` and `actions` add a header row; `padding` and `width` control its box. `ui.card` · Category: [Display](https://albakore.github.io/pyzed/library/#display) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#card) **Code:** ```python ui.card( pz.column([ ui.muted("Pyzed draws the UI with Iced, in Rust."), pz.row([pz.hspace(), ui.button("Cancel", on_cancel, variant="ghost"), ui.button("OK", on_ok, variant="solid")], spacing=8), ], spacing=12), title="Card", actions=[ui.icon_button("ellipsis", on_menu, size="sm")], width=380, ) ``` #### When to use - To group related content on a page: a summary, a form section, a dashboard tile. - For a dialog over the UI use [Modal](https://albakore.github.io/pyzed/library/modal/). #### Usage ```python import pyzed as pz from pyzed import ui ui.card( pz.column([ ui.muted("Pyzed draws the UI with Iced, in Rust."), pz.row([pz.hspace(), ui.button("Cancel", on_cancel, variant="ghost"), ui.button("OK", on_ok, variant="solid")], spacing=8), ], spacing=12), title="Card", actions=[ui.icon_button("ellipsis", on_menu, size="sm")], width=380, ) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python ui.card(ui.muted("A bordered surface."), width=260) ``` **} alt={** ```python ui.card(ui.muted("Three files changed."), title="Changes", width=260) ``` ```python ui.card(ui.muted("Three files changed."), title="Changes", actions=[ui.icon_button("ellipsis", on_menu, size="sm")], width=260) ``` ##### Padding ```python ui.card(ui.label("Compact"), padding=8) ``` ```python ui.card(ui.label("Default")) ``` ```python ui.card(ui.label("Roomy"), padding=28) ``` ##### States and events ```python ui.card(ui.muted("Python app with a window"), title="Desktop app", on_press=on_press, selected=True, width=260) ``` ```python ui.card(ui.muted("3 files changed"), title="Commit", footer=[ui.button("Push", on_press)], elevated=True, width=260) ``` #### Events Card has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `()` | Makes the whole card clickable. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Plans(pz.App): def __init__(self): self.plan = "Pro" def view(self): return pz.row([ ui.card(ui.muted(f"Plan {name}"), title=name, width=160, selected=name == self.plan, on_press=lambda name=name: setattr(self, "plan", name)) # the whole card for name in ("Free", "Pro", "Team") ], spacing=8) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Choose: plan: str class Plans(pz.App): plan = "Pro" def update(self, message): match message: case Choose(plan): self.plan = plan def view(self): return pz.row([ui.card(ui.muted(name), title=name, width=160, selected=name == self.plan, on_press=Choose(name)) for name in ("Free", "Pro", "Team")], spacing=8) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: plan: str = "Pro" def plan_card(name, selected, choose): # a small function component return ui.card(ui.muted(name), title=name, width=160, selected=selected, on_press=choose) def view(state, set_state): return pz.row([plan_card(n, n == state.plan, lambda n=n: set_state(plan=n)) for n in ("Free", "Pro", "Team")], spacing=8) ``` #### Properties and API ##### `ui.card` ```python card( content, *, title=None, actions=(), padding=16, width=None, footer=(), on_press=None, selected=False, elevated=False, theme=None, ) ``` A bordered surface to group content, with an optional title and actions. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `title` | `None` | Title. | | `actions` | `()` | Extra widgets (usually buttons) shown as actions. | | `padding` | `16` | Inner padding. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `footer` | `()` | Widgets at the bottom right (buttons). | | `selected` | `False` | Outlines it in the accent color. | | `elevated` | `False` | Adds a shadow. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#card) #### Related - [Modal](https://albakore.github.io/pyzed/library/modal/): A dialog surface with title, content and footer buttons. - [Settings group](https://albakore.github.io/pyzed/library/settings-group/): A titled block of field rows, for settings screens. - [Empty state](https://albakore.github.io/pyzed/library/empty-state/): A centered placeholder for empty lists and searches. ### Catalog > Things to install, with a search box and Install or Update. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/catalog/ :::tip[In plain words] A searchable shop-like list of add-ons, each with an Install button. ::: `ui.Catalog` is a component for things to install (agents from a registry, MCP servers, skills): a search box over a scrolling list where each row shows the name, `version` and `description`, and on the right Install, Installed or Update to a newer version. `items` are dicts or objects with `id`, `name` and optional `version`, `description`, `installed` (a bool) and `update` (the newer version). Install and Update report `on_install` with the item's id in `event.value`; while `busy` holds an id, that row shows a spinner and the other Install buttons are disabled. `height` is the list's height. `ui.Catalog` · Category: [AI agents](https://albakore.github.io/pyzed/library/#ai-agents) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#catalog) **Code:** ```python pz.container(ui.Catalog(items=[ {"id": "gemini", "name": "Gemini CLI", "version": "0.64.0", "description": "A coding agent for the terminal.", "installed": True, "update": "0.65.0"}, {"id": "codex", "name": "Codex CLI", "version": "0.40.0", "description": "Writes and runs code for you."}, {"id": "goose", "name": "Goose", "version": "1.9.0", "description": "An open source agent.", "installed": True}, {"id": "opencode", "name": "OpenCode", "version": "0.12.1", "description": "An agent that edits whole projects."}, ], busy="codex", height=220, on_install=on_install), width=460) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - To add agents, MCP servers, skills or plugins from a list, inside a dialog or a settings page. #### Usage ```python import pyzed as pz from pyzed import ui class Agents(pz.App): def __init__(self): self.registry = load_registry() # [{"id", "name", "version", "description", "installed"}, ...] self.installing = "" def view(self): return ui.Catalog(items=self.registry, busy=self.installing, on_install=lambda e: self.install(e.value)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### State While one item installs, the other Install buttons are disabled. ```python pz.container(ui.Catalog(items=[{"id": "goose", "name": "Goose", "version": "1.9.0", "description": "An open source agent."}], height=50), width=380) ``` ```python pz.container(ui.Catalog(items=[{"id": "goose", "name": "Goose", "version": "1.9.0", "description": "An open source agent.", "installed": True}], height=50), width=380) ``` ```python pz.container(ui.Catalog(items=[{"id": "goose", "name": "Goose", "version": "1.9.0", "description": "An open source agent.", "installed": True, "update": "2.0.0"}], height=50), width=380) ``` ```python pz.container(ui.Catalog(items=[ {"id": "goose", "name": "Goose", "version": "1.9.0", "description": "An open source agent."}, {"id": "codex", "name": "Codex CLI", "version": "0.40.0", "description": "Writes and runs code."}, ], busy="goose", height=100), width=380) ``` ```python pz.container(ui.Catalog(items=[{"id": "goose", "name": "Goose"}], height=50), width=380) ``` #### Events Catalog has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Handler gets | When | | --- | --- | --- | | `on_install` | `(event)` | Install or Update was pressed (`event.value` is the id). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Agents(pz.App): def __init__(self): self.items = [{"id": "goose", "name": "Goose", "version": "1.9.0"}, {"id": "codex", "name": "Codex CLI", "version": "0.40.0"}] self.installing = "" def install(self, ident): # on_install: event.value is the item's id self.installing = ident def view(self): return ui.Catalog(items=self.items, busy=self.installing, height=200, on_install=lambda e: self.install(e.value)) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Install: ident: str class Agents(pz.App): items = [{"id": "goose", "name": "Goose", "version": "1.9.0"}] installing = "" def update(self, message): match message: case Install(ident): self.installing = ident def view(self): return ui.Catalog(items=self.items, busy=self.installing, height=200, on_install=lambda e: Install(e.value)) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: installed: frozenset = frozenset() ITEMS = [{"id": "goose", "name": "Goose", "version": "1.9.0"}] def view(state, set_state): items = [{**i, "installed": i["id"] in state.installed} for i in ITEMS] return ui.Catalog(items=items, height=200, on_install=lambda e: set_state(installed=state.installed | {e.value})) ``` #### Properties and API ##### `ui.Catalog` ```python class Catalog ``` A component for things to install with a search box (agents from a registry, servers, skills…): each row shows Install, Installed or Update to a newer version. | Property | Default | Description | | --- | --- | --- | | `items` | `None` | Dicts or objects with `id`, `name` and optional `version`, `description`, `installed` and `update`. | | `busy` | `""` | The id being installed (a spinner). | | `height` | `320` | Height of the list. | | `theme` | `None` | Theme. | Events: `on_install` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#catalog) #### Related - [Service row](https://albakore.github.io/pyzed/library/service-row/): A settings row for an MCP server, agent or skill: status, switch and menu. - [Search input](https://albakore.github.io/pyzed/library/search-input/): An input with a magnifying glass, for filtering. - [List item](https://albakore.github.io/pyzed/library/list-item/): A list row with icon, text and an end slot. ### Checkbox > A checkbox with an optional label. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/checkbox/ :::tip[In plain words] A square you tick to say yes to an option. ::: A themed checkbox. `on_toggle` receives the new `bool`; `label` adds clickable text next to it. `ui.checkbox` · Category: [Forms](https://albakore.github.io/pyzed/library/#forms) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#checkbox) **Code:** ```python pz.column([ ui.checkbox(True, on_toggle, label="Format on save"), ui.checkbox(False, on_toggle, label="Show hidden files"), ui.checkbox(True, on_toggle, label="Use tabs"), ], spacing=10) ``` #### When to use - For options that are applied later (a form you submit) or a list of independent choices. - For a setting that takes effect at once, a [Switch](https://albakore.github.io/pyzed/library/switch/) reads better. #### Usage ```python import pyzed as pz from pyzed import ui class Settings(pz.App): def __init__(self): self.accepted = False def view(self): return ui.checkbox(self.accepted, lambda value: setattr(self, "accepted", value), label="I accept the terms") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### State ```python ui.checkbox(True, on_toggle, label="Format on save") ``` ```python ui.checkbox(False, on_toggle, label="Format on save") ``` ```python ui.checkbox(True, label="Managed by your admin") ``` ##### Content ```python ui.checkbox(True, on_toggle) ``` ```python pz.column([ui.checkbox(True, on_toggle, label="Python"), ui.checkbox(False, on_toggle, label="Rust"), ui.checkbox(True, on_toggle, label="TypeScript")], spacing=8) ``` ##### States and events ```python ui.checkbox(None, on_toggle, label="Some files") ``` ```python ui.checkbox(True, on_toggle, label="Locked", disabled=True) ``` ```python ui.checkbox(True, on_toggle, label="Small", size="sm") ``` ```python ui.checkbox(True, on_toggle, label="Large", size="lg") ``` ##### Base widget The `pz.*` widget underneath: no theme, every color and size is yours. ```python pz.checkbox(True, "pz.checkbox", on_toggle=on_toggle, accent="#c678dd", size=18) ``` #### Events Checkbox has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_toggle` | `ui.checkbox`, `pz.checkbox` | `(checked)` | Callable that receives the new `bool` (or a message to send). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Settings(pz.App): def __init__(self): self.options = {"Format on save": True, "Show hidden files": False} def toggle(self, name, checked): # on_toggle gets True or False self.options[name] = checked def view(self): return pz.column([ ui.checkbox(on, lambda checked, name=name: self.toggle(name, checked), label=name) for name, on in self.options.items() ], spacing=10) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Toggle: name: str checked: bool class Settings(pz.App): options = {"Format on save": True, "Show hidden files": False} def update(self, message): match message: case Toggle(name, checked): self.options = {**self.options, name: checked} def view(self): return pz.column([ui.checkbox(on, lambda c, n=name: Toggle(n, c), label=name) for name, on in self.options.items()], spacing=10) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: format_on_save: bool = True hidden_files: bool = False def view(state, set_state): return pz.column([ ui.checkbox(state.format_on_save, lambda c: set_state(format_on_save=c), label="Format on save"), ui.checkbox(state.hidden_files, lambda c: set_state(hidden_files=c), label="Show hidden files"), ], spacing=10) ``` #### Tips :::tip Once clicked or reached with Tab it has the keyboard focus (a ring shows when you use the keys): Space toggles it. ::: #### Properties and API ##### `ui.checkbox` ```python checkbox( checked, on_toggle=None, *, label=None, size='md', disabled=False, id=None, theme=None, ) ``` A checkbox. `checked=None` shows the mixed state (part of a group checked); clicking it checks it. | Property | Default | Description | | --- | --- | --- | | `checked` | *required* | Current state. | | `label` | `None` | Label text. | | `size` | `"md"` | `"sm"`, `"md"` or `"lg"`. | | `disabled` | `False` | Greys it out and ignores clicks. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_toggle` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#checkbox) ##### `pz.checkbox` ```python checkbox( checked, label=None, *, on_toggle=None, size=None, text_size=None, accent=None, bg=None, border_color=None, check_color=None, color=None, ) ``` A checkbox. | Property | Default | Description | | --- | --- | --- | | `checked` | *required* | Current state. | | `label` | `None` | Label text. | | `size` | `None` | Box size. | | `text_size` | `None` | Text size. | | `accent` | `None` | Accent color (active part). | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `border_color` | `None` | Border color. | | `check_color` | `None` | Check mark color. | | `color` | `None` | Text or icon color. | Events: `on_toggle` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#checkbox) #### Related - [Switch](https://albakore.github.io/pyzed/library/switch/): An on/off switch for settings that apply at once. - [Radio group](https://albakore.github.io/pyzed/library/radio-group/): Mutually exclusive options as radio buttons. - [Field](https://albakore.github.io/pyzed/library/field/): A settings row: title and description left, control right. ### Chip > A compact tag: clickable as a filter, removable with an ✕. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/chip/ :::tip[In plain words] A small rounded tag. Click it to turn a filter on or off, or press its ✕ to remove it. ::: A small rounded tag. With `on_press` it acts as a filter you can toggle (`selected=True` highlights it), and with `on_remove` it shows a close button, as in a list of tags. `ui.chip` · Category: [Actions](https://albakore.github.io/pyzed/library/#actions) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#chip) **Code:** ```python pz.row([ ui.chip("python", icon="tag", selected=True, on_press=on_filter), ui.chip("rust", on_press=on_filter), ui.chip("iced", on_remove=on_remove), ui.chip("zed", icon="sparkles", on_remove=on_remove), ], spacing=6) ``` #### When to use - For tags, filters and selected values (a multi-select, recipients of a message). - For read-only statuses use a [Badge](https://albakore.github.io/pyzed/library/badge/). #### Usage ```python import pyzed as pz from pyzed import ui class Tags(pz.App): def __init__(self): self.tags = ["python", "rust", "iced"] def view(self): return pz.row([ui.chip(t, on_remove=lambda t=t: self.tags.remove(t)) for t in self.tags], spacing=6, wrap=True) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Kind ```python ui.chip("python") ``` ```python ui.chip("rust", on_press=on_filter) ``` ```python ui.chip("python", on_press=on_filter, selected=True) ``` ```python ui.chip("iced", on_remove=on_remove) ``` ##### Content ```python ui.chip("design", icon="tag") ``` ```python ui.chip("ada@example.com", icon="user", on_remove=on_remove) ``` ```python ui.chip("favorites", icon="star", selected=True, on_press=on_filter) ``` ##### States and events ```python ui.chip("Failing", on_press=on_press, selected=True, tint="error") ``` ```python ui.chip("Archived", on_press=on_press, on_remove=on_remove, disabled=True) ``` #### Events Chip has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `()` | Message or callable sent on press. `None` disables the control. | | `on_remove` | `()` | Shows a ✕ that sends this when clicked. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Filters(pz.App): def __init__(self): self.tags = ["python", "rust", "iced"] self.active = "python" def view(self): return pz.row([ ui.chip(t, selected=t == self.active, on_press=lambda t=t: setattr(self, "active", t), # pick it on_remove=lambda t=t: self.tags.remove(t)) # its ✕ for t in self.tags ], spacing=6, wrap=True) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Pick: tag: str @dataclass class Remove: tag: str class Filters(pz.App): tags = ["python", "rust", "iced"] active = "python" def update(self, message): match message: case Pick(tag): self.active = tag case Remove(tag): self.tags = [t for t in self.tags if t != tag] def view(self): return pz.row([ui.chip(t, selected=t == self.active, on_press=Pick(t), on_remove=Remove(t)) for t in self.tags], spacing=6, wrap=True) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: tags: tuple = ("python", "rust", "iced") active: str = "python" def view(state, set_state): return pz.row([ ui.chip(t, selected=t == state.active, on_press=lambda t=t: set_state(active=t), on_remove=lambda t=t: set_state(tags=tuple(x for x in state.tags if x != t))) for t in state.tags ], spacing=6, wrap=True) ``` #### Properties and API ##### `ui.chip` ```python chip( content, *, on_press=None, on_remove=None, selected=False, icon=None, tint='accent', disabled=False, theme=None, ) ``` A compact tag, optionally clickable (filters) and with a button to remove it. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Text. | | `selected` | `False` | Marks it as selected. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `tint` | `"accent"` | Color when selected (a theme token). | | `disabled` | `False` | Greys it out and ignores presses. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_press`, `on_remove` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#chip) #### Related - [Badge](https://albakore.github.io/pyzed/library/badge/): A small pill for statuses, versions and counters. - [Toggle group](https://albakore.github.io/pyzed/library/toggle-group/): An icon-only segmented control. ### Choice > A message with your own buttons. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/choice/ :::tip[In plain words] A question with several possible answers, each one a button. ::: A message with your own buttons: `options` are `(label, on_press)` pairs and the last one is the main one. `ui.choice` · Category: [Dialogs](https://albakore.github.io/pyzed/library/#dialogs) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#choice) **Code:** ```python ui.dialog_layer(main_view(), ui.choice( "notes.py already exists in this folder.", [("Keep both", on_keep), ("Skip", on_skip), ("Replace", on_replace)], on_cancel, title="File exists", width=420, )) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - When a question has more than two answers (Keep both / Replace / Skip). #### Usage ```python from pyzed import ui ui.dialog_layer(main_view(), ui.choice( "notes.py already exists in this folder.", [("Keep both", on_keep), ("Skip", on_skip), ("Replace", on_replace)], on_cancel, title="File exists", width=420, )) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python ui.choice("Open the project in…", [("This window", on_here), ("New window", on_new)], on_cancel, width=360) ``` ```python ui.choice("notes.py already exists.", [("Keep both", on_keep), ("Skip", on_skip), ("Replace", on_replace)], on_cancel, title="File exists", width=400) ``` #### Events Choice has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_cancel` | `()` | The close icon. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Copy(pz.App): def __init__(self): self.asking, self.answer = True, None def answer_with(self, what): self.asking, self.answer = False, what def view(self): dialog = ui.choice("notes.py already exists in this folder.", [("Keep both", lambda: self.answer_with("both")), # one handler per option ("Replace", lambda: self.answer_with("replace"))], lambda: setattr(self, "asking", False), # on_cancel: the ✕ title="File exists") return ui.dialog_layer(main_view(), dialog if self.asking else None) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Answer: what: str class Copy(pz.App): asking = True def update(self, message): match message: case Answer(what): self.asking = False print("chose", what) case "cancel": self.asking = False def view(self): dialog = ui.choice("notes.py already exists.", [("Keep both", Answer("both")), ("Replace", Answer("replace"))], "cancel") return ui.dialog_layer(main_view(), dialog if self.asking else None) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: answer: str = "" def view(state, set_state): if state.answer: return ui.label(f"You chose: {state.answer}") return ui.dialog_layer(main_view(), ui.choice( "notes.py already exists.", [(label, lambda a=answer: set_state(answer=a)) for label, answer in (("Keep both", "both"), ("Replace", "replace"))], lambda: set_state(answer="cancel"))) ``` #### Properties and API ##### `ui.choice` ```python choice(message, options, on_cancel, *, title=None, width=440, theme=None) ``` A message with your own buttons. | Property | Default | Description | | --- | --- | --- | | `message` | *required* | Any Python value, or a callable. | | `options` | *required* | `(label, on_press)` pairs; the last one is the main button. | | `title` | `None` | Title. | | `width` | `440` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_cancel` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#choice) #### Related - [Confirm](https://albakore.github.io/pyzed/library/confirm/): A yes/no question, red for destructive actions. - [Unsaved changes](https://albakore.github.io/pyzed/library/unsaved-changes/): “Save your changes before closing?” ### Color picker > Pick a color, a gradient or a masked fill; swatches show them. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/color-picker/ :::tip[In plain words] A palette to choose a color, its transparency, or a blend of colors. ::: `ui.ColorPicker` is a component that picks a color with alpha, a linear gradient (stops you add, drag and remove, plus an angle) or a fill with an opacity mask. `on_change` receives an event whose `value` is a `"#rrggbb[aa]"` string, a `pz.Gradient` or a `pz.Paint`, all valid backgrounds. `ui.color_swatch` shows any of them over a checkerboard. `ui.ColorPicker` · Category: [Forms](https://albakore.github.io/pyzed/library/#forms) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#colorpicker) **Code:** ```python pz.row([ ui.ColorPicker(value="#3b82f6cc", on_change=on_change), pz.column([ ui.color_swatch("#3b82f6", size=28), ui.color_swatch("#a1c181aa", size=28), ui.color_swatch(pz.Gradient(["#f97316", "#7c3aed"], angle=90), size=28), ], spacing=8), ], spacing=16) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For theme editors, drawing apps and style properties. - Show a `color_swatch` and open the picker in a [Popover](https://albakore.github.io/pyzed/library/popover/) when it is pressed. #### Usage ```python import pyzed as pz from pyzed import ui class Styles(pz.App): def __init__(self): self.fill = "#3b82f6" def view(self): return pz.row([ ui.ColorPicker(value=self.fill, on_change=lambda e: setattr(self, "fill", e.value)), pz.container(width=120, height=120, bg=self.fill, radius=8), ], spacing=16) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python ui.ColorPicker(value="#3b82f6cc", on_change=on_change) ``` ```python ui.ColorPicker(value="#a1c181", alpha=False, gradients=False, masks=False, on_change=on_change) ``` ```python ui.ColorPicker(value="#e5c07b", gradients=False, masks=False, swatches=["#e06c75", "#e5c07b", "#98c379", "#61afef", "#c678dd"], on_change=on_change) ``` ##### Swatches A swatch draws any color, gradient or paint over a checkerboard, so transparency shows. ```python ui.color_swatch("#3b82f6", size=32) ``` ```python ui.color_swatch("#a1c181aa", size=32) ``` ```python ui.color_swatch(pz.Gradient(["#f97316", "#7c3aed"], angle=90), size=32) ``` ```python ui.checkerboard(96, 48, size=8) ``` #### Events Color picker has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_change` | `ui.ColorPicker` | `(event)` | Receives `event.value`. | | `on_press` | `ui.color_swatch` | `()` | Makes it clickable. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Styles(pz.App): def __init__(self): self.fill = "#3b82f6" def picked(self, event): # a pz.Component: the color is event.value self.fill = event.value def view(self): return pz.row([ ui.ColorPicker(value=self.fill, on_change=self.picked), pz.container(width=80, height=80, bg=self.fill, radius=8), ui.color_swatch("#ef4444", on_press=lambda: setattr(self, "fill", "#ef4444")), ], spacing=16) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Fill: color: str class Styles(pz.App): fill = "#3b82f6" def update(self, message): match message: case Fill(color): self.fill = color def view(self): return pz.row([ui.ColorPicker(value=self.fill, on_change=lambda e: Fill(e.value)), ui.color_swatch("#ef4444", on_press=Fill("#ef4444"))], spacing=16) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: fill: str = "#3b82f6" def view(state, set_state): return pz.row([ui.ColorPicker(value=state.fill, on_change=lambda e: set_state(fill=e.value)), pz.container(width=80, height=80, bg=state.fill, radius=8)], spacing=16) ``` #### Properties and API ##### `ui.ColorPicker` ```python class ColorPicker ``` A component that picks a color with alpha, a linear gradient (stops you add, drag and remove, plus an angle) or a fill with an opacity mask. `on_change` gets a `"#rrggbb[aa]"` string, a `pz.Gradient` or a `pz.Paint`, all valid as a `background`. Pass the picked value back as `value`. See [Styles](https://albakore.github.io/pyzed/theming/styles/#color-picker). | Property | Default | Description | | --- | --- | --- | | `value` | `"#3b82f6"` | A color, theme token, `pz.Gradient` or `pz.Paint`. | | `alpha` | `True` | Shows the alpha bar and field. | | `gradients` | `True` | Shows the Solid/Gradient switch. | | `masks` | `True` | Shows the mask editor. | | `swatches` | `None` | Quick colors (default: the theme's accent and status colors). | Events: `on_change` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#colorpicker) ##### `ui.color_swatch` ```python color_swatch(value, *, size=20, on_press=None) ``` A small square showing a color, gradient or paint over a checkerboard. | Property | Default | Description | | --- | --- | --- | | `value` | *required* | What to show. | | `size` | `20` | Side in pixels. | Events: `on_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#color_swatch) ##### `ui.checkerboard` ```python checkerboard(width, height, size=6) ``` A light/dark checkerboard to draw under translucent colors. | Property | Default | Description | | --- | --- | --- | | `width` | *required* | Width. | | `height` | *required* | Height. | | `size` | `6` | Cell size. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#checkerboard) #### Related - [Popover](https://albakore.github.io/pyzed/library/popover/): Floating content at a point: context menus, color pickers. - [Card](https://albakore.github.io/pyzed/library/card/): A bordered surface with an optional title and actions. ### Column > Stacks children vertically. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/column/ :::tip[In plain words] Puts things one under the other, from top to bottom. ::: Stacks its children vertically, with `spacing`, `padding`, `align` on the cross axis and an optional `max_width`. Like `row`, nested lists are flattened and `None`/`False` are ignored. `pz.column` · Category: [Layout](https://albakore.github.io/pyzed/library/#layout) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#column) **Code:** ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.row([ pz.column([box("1"), box("2"), box("3")], spacing=8), pz.column([box("wide", w=160), box("center"), box("end")], spacing=8, align="center"), pz.column([box("top"), pz.vspace(), box("bottom")], spacing=8, height=170), ], spacing=32) ``` #### When to use - For forms, lists, page content and most `view()` roots. #### Usage ```python import pyzed as pz from pyzed import ui box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.row([ pz.column([box("1"), box("2"), box("3")], spacing=8), pz.column([box("wide", w=160), box("center"), box("end")], spacing=8, align="center"), pz.column([box("top"), pz.vspace(), box("bottom")], spacing=8, height=170), ], spacing=32) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Cross-axis alignment ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.column([box("wide", w=160), box("B"), box("C")], spacing=8, align="start") ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.column([box("wide", w=160), box("B"), box("C")], spacing=8, align="center") ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.column([box("wide", w=160), box("B"), box("C")], spacing=8, align="end") ``` ##### Options ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.column([box("1"), box("2")], spacing=16) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.column([box("top"), pz.vspace(), box("bottom")], height=170) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.column([box("1"), box("2")], spacing=8, padding=16), border_color=pz.theme.current().border, border_width=1, radius=8) ``` #### Events Column has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.column` ```python column( children=None, *, spacing=0.0, padding=None, width=None, height=None, align=None, max_width=None, clip=False, ) ``` Stacks its children vertically. | Property | Default | Description | | --- | --- | --- | | `children` | `None` | List of children. Nested lists are flattened and `None` and `False` are ignored, so you can write `cond and widget`. | | `spacing` | `0.0` | Space between children, in pixels. | | `padding` | `None` | Inner padding: `8`, `(vertical, horizontal)` or `(top, right, bottom, left)`. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `align` | `None` | Alignment of the children on the cross axis: `"start"`, `"center"` or `"end"`. | | `max_width` | `None` | Maximum width in pixels. | | `clip` | `False` | Clips content that overflows the bounds. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#column) #### Related - [Row](https://albakore.github.io/pyzed/library/row/): Lays out children horizontally. - [Scrollable](https://albakore.github.io/pyzed/library/scrollable/): Scrolls content that doesn't fit. - [Space](https://albakore.github.io/pyzed/library/spacing/): Fixed gaps and flexible spacers. ### Command palette > A command palette with fuzzy search and shortcuts. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/command-palette/ :::tip[In plain words] A search box for every action of the app: type what you want to do and press Enter. ::: A command palette: it fuzzy-filters `commands` (`ui.PaletteItem(label, on_press, keys=)`) by `query`, highlights the matched letters and shows each shortcut. You own the query and the `selected` index; Enter calls `on_submit`. `ui.command_palette` · Category: [Overlays](https://albakore.github.io/pyzed/library/#overlays) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#command_palette) **Code:** ```python ui.command_palette("tog", on_query, [ ui.PaletteItem("editor: toggle soft wrap", on_wrap, keys="alt-z"), ui.PaletteItem("theme selector: toggle", on_theme, keys="ctrl-k ctrl-t"), ui.PaletteItem("workspace: toggle left dock", on_left, keys="ctrl-b"), ui.PaletteItem("terminal panel: toggle", on_terminal, keys="ctrl-j"), ], selected=0, width=520) ``` #### When to use - To make every action reachable from the keyboard (usually with Ctrl+Shift+P). #### Usage ```python import pyzed as pz from pyzed import ui class App(pz.App): def __init__(self): self.open, self.query, self.selected = False, "", 0 def commands(self): return [ui.PaletteItem("editor: toggle soft wrap", self.toggle_wrap, keys="alt-z"), ui.PaletteItem("workspace: toggle left dock", self.toggle_left, keys="ctrl-b")] def on_key(self, combo): if combo == "ctrl-shift-p": self.open, self.query, self.selected = True, "", 0 return pz.Command.focus("command-palette") if self.open and combo in ("up", "down"): self.selected += 1 if combo == "down" else -1 elif combo == "escape": self.open = False def run_selected(self): matches = ui.fuzzy_filter(self.query, self.commands(), key=lambda c: c.label) if matches: self.open = False return matches[self.selected % len(matches)][0].on_press() def view(self): palette = ui.command_palette(self.query, lambda q: setattr(self, "query", q), self.commands(), selected=self.selected, on_submit=self.run_selected) return ui.layer(self.main_view(), palette if self.open else None, on_dismiss=lambda: setattr(self, "open", False)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Query ```python ui.command_palette("", on_query, [ ui.PaletteItem("file: new", on_new, keys="ctrl-n"), ui.PaletteItem("file: open", on_open, keys="ctrl-o"), ui.PaletteItem("theme selector: toggle", on_theme), ], width=420) ``` ```python ui.command_palette("op", on_query, [ ui.PaletteItem("file: new", on_new, keys="ctrl-n"), ui.PaletteItem("file: open", on_open, keys="ctrl-o"), ui.PaletteItem("workspace: open recent", on_recent, keys="ctrl-r"), ], width=420) ``` ```python ui.command_palette("", on_query, [ ui.PaletteItem("file: new", on_new, keys="ctrl-n"), ui.PaletteItem("file: open", on_open, keys="ctrl-o"), ui.PaletteItem("file: save", on_save, keys="ctrl-s"), ], selected=1, width=420) ``` #### Events Command palette has **3 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_query` | `ui.command_palette` | `(text)` | Callable that receives the new text. | | `on_submit` | `ui.command_palette` | `()` | Message or callable sent when Enter is pressed. | | `on_press` | `ui.PaletteItem` | `()` | Message or callable sent on press. `None` disables the control. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class App(pz.App): def __init__(self): self.open, self.query, self.wrap = True, "", False def toggle_wrap(self): self.wrap, self.open = not self.wrap, False def commands(self): # each item's on_press runs the command return [ui.PaletteItem("editor: toggle soft wrap", self.toggle_wrap, keys="alt-z")] def run_first(self): # on_submit: Enter runs the first match matches = ui.fuzzy_filter(self.query, self.commands(), key=lambda c: c.label) return matches[0][0].on_press() if matches else None def view(self): palette = ui.command_palette(self.query, lambda q: setattr(self, "query", q), # on_query self.commands(), on_submit=self.run_first) return ui.layer(main_view(), palette if self.open else None, on_dismiss=lambda: setattr(self, "open", False)) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Query: text: str class App(pz.App): open, query, wrap = True, "", False def update(self, message): match message: case Query(text): self.query = text case "toggle wrap" | "submit": self.wrap, self.open = not self.wrap, False def view(self): palette = ui.command_palette(self.query, Query, [ui.PaletteItem("editor: toggle soft wrap", "toggle wrap")], on_submit="submit") return ui.layer(main_view(), palette if self.open else None) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: query: str = "" wrap: bool = False def view(state, set_state): items = [ui.PaletteItem("editor: toggle soft wrap", lambda: set_state(wrap=not state.wrap))] return ui.command_palette(state.query, lambda q: set_state(query=q), items, on_submit=lambda: set_state(wrap=not state.wrap)) ``` #### Properties and API ##### `ui.command_palette` ```python command_palette( query, on_query, commands, *, selected=0, on_submit=None, placeholder='Execute a command…', input_id='command-palette', theme=None, **kwargs, ) ``` A command palette: fuzzy-filters `commands` by `query` and shows their shortcuts. | Property | Default | Description | | --- | --- | --- | | `query` | *required* | Search text. | | `commands` | *required* | List of `PaletteItem`. | | `selected` | `0` | Highlighted index (for arrow-key navigation). | | `placeholder` | `"Execute a command…"` | Hint text shown when empty. | | `input_id` | `"command-palette"` | Field id (for `Command.focus`). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | | `**kwargs` | — | Same as `picker`. | Events: `on_query`, `on_submit` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#command_palette) ##### `ui.PaletteItem` ```python @dataclass class PaletteItem(label, on_press=None, keys=None, icon=None, detail=None) ``` An entry of `command_palette` or `picker`. | Property | Default | Description | | --- | --- | --- | | `label` | *required* | Label text. | | `keys` | `None` | Shortcut shown at the end, written as a string: `"ctrl-s"`, `"cmd-k cmd-s"`. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `detail` | `None` | Secondary text (for example, a file path). | Events: `on_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#paletteitem) #### Related - [Picker](https://albakore.github.io/pyzed/library/picker/): A searchable list on a floating surface, with fuzzy matching. - [Layer](https://albakore.github.io/pyzed/library/layer/): Draws an overlay over your view; clicking outside dismisses it. - [Kbd](https://albakore.github.io/pyzed/library/kbd/): Keyboard shortcuts drawn as keys, with symbols on macOS. ### Confirm > A yes/no question, red for destructive actions. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/confirm/ :::tip[In plain words] Asks “are you sure?” before doing something that can't be undone. ::: Asks a yes/no question. `danger=True` paints the confirm button red; `confirm_label` and `cancel_label` rename the buttons. `ui.confirm` · Category: [Dialogs](https://albakore.github.io/pyzed/library/#dialogs) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#confirm) **Code:** ```python ui.dialog_layer(main_view(), ui.confirm( "Delete notes.py? This can't be undone.", on_delete, on_cancel, title="Delete file", danger=True, confirm_label="Delete", width=360, )) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - Before destructive or irreversible actions: delete, overwrite, discard. #### Usage ```python from pyzed import ui ui.dialog_layer(main_view(), ui.confirm( "Delete notes.py? This can't be undone.", on_delete, on_cancel, title="Delete file", danger=True, confirm_label="Delete", width=360, )) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Kind ```python ui.confirm("Close all tabs?", on_confirm, on_cancel, title="Close tabs", width=320) ``` ```python ui.confirm("Delete notes.py?", on_delete, on_cancel, title="Delete file", danger=True, confirm_label="Delete", width=320) ``` ```python ui.confirm("Overwrite the existing file?", on_confirm, on_cancel, kind="warning", width=320) ``` ```python ui.confirm("Push 3 commits to main?", on_push, on_cancel, confirm_label="Push", cancel_label="Not now", width=320) ``` #### Events Confirm has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_confirm` | `()` | The confirm button. | | `on_cancel` | `()` | Cancel, the close icon. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Files(pz.App): def __init__(self): self.files = ["notes.py", "todo.txt"] self.deleting = "notes.py" # the file waiting for an answer def delete(self): # on_confirm self.files.remove(self.deleting) self.deleting = None def view(self): dialog = None if self.deleting: dialog = ui.confirm(f"Delete {self.deleting}?", self.delete, lambda: setattr(self, "deleting", None), # on_cancel title="Delete file", danger=True, confirm_label="Delete") return ui.dialog_layer(main_view(), dialog) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Delete: name: str class Files(pz.App): files = ["notes.py", "todo.txt"] deleting = "notes.py" def update(self, message): match message: case Delete(name): self.files = [f for f in self.files if f != name] self.deleting = None case "cancel": self.deleting = None def view(self): dialog = ui.confirm(f"Delete {self.deleting}?", Delete(self.deleting), "cancel", danger=True) \ if self.deleting else None return ui.dialog_layer(main_view(), dialog) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: files: tuple = ("notes.py", "todo.txt") deleting: str = "notes.py" def view(state, set_state): if not state.deleting: return main_view() keep = tuple(f for f in state.files if f != state.deleting) return ui.dialog_layer(main_view(), ui.confirm( f"Delete {state.deleting}?", lambda: set_state(files=keep, deleting=""), lambda: set_state(deleting=""), danger=True)) ``` #### Properties and API ##### `ui.confirm` ```python confirm( message, on_confirm, on_cancel, *, title=None, confirm_label=None, cancel_label=None, danger=False, kind=None, width=420, theme=None, ) ``` Asks a yes/no question. | Property | Default | Description | | --- | --- | --- | | `message` | *required* | Text or widget. | | `title` | `None` | Title. | | `confirm_label` | `None` | Confirm button text. | | `cancel_label` | `None` | Cancel button text. | | `danger` | `False` | Paints the confirm button red and labels it Delete. | | `kind` | `None` | Adds an icon, as in `alert`. | | `width` | `420` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_confirm`, `on_cancel` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#confirm) #### Related - [Alert](https://albakore.github.io/pyzed/library/alert/): A message with one button. - [Choice](https://albakore.github.io/pyzed/library/choice/): A message with your own buttons. - [Unsaved changes](https://albakore.github.io/pyzed/library/unsaved-changes/): “Save your changes before closing?” ### Console > A dev-tools style log with levels, filter, copy and clear. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/console/ :::tip[In plain words] A list of messages from the app (info, warnings, errors) that you can filter and copy. ::: `ui.Log` collects entries (thread-safe, capped at `limit`, repeated lines folded) and can capture `print` and tracebacks. `ui.console` shows them like a browser's dev tools console: a filter box, one toggle per level with its count, copy and clear. Levels are `debug`, `info`, `event`, `stdout`, `stderr`, `warning` and `error` (`ui.LOG_LEVELS`). With a `ui.LogSelection` the lines can be selected (click, Shift+click, Ctrl+click) and a selected line shows its `detail` (a traceback); `on_context` opens your menu on right click, and `sources` adds a dropdown to show the lines of one source. `ui.console` · Category: [Code and tools](https://albakore.github.io/pyzed/library/#code-and-tools) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#console) **Code:** ```python log = ui.Log() log.write("info", "Loaded ui/main.pzform") log.write("event", "button1.click") log.write("stdout", "Saving 3 files…") log.write("warning", "settings.json not found, using defaults") log.write("error", "ValueError: invalid literal for int()") pz.container(ui.console(log.entries, on_clear=on_clear, on_copy=on_copy, on_query=on_query), width=600, height=220) ``` #### When to use - For a debug panel in your app, or to show what a background job is doing. #### Usage ```python import pyzed as pz from pyzed import ui class Debug(pz.App): def __init__(self): self.log = ui.Log(on_write=lambda: pz.post("log")) # redraw when a line arrives self.log.capture() # also collect print() and stderr self.query, self.hidden = "", set() def view(self): return ui.console(self.log.entries, query=self.query, on_query=lambda q: setattr(self, "query", q), hidden=self.hidden, on_toggle_level=lambda lvl: self.hidden.symmetric_difference_update({lvl}), on_clear=self.log.clear, on_copy=lambda: pz.Command.copy(self.log.text())) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python log = ui.Log() for level in ui.LOG_LEVELS: log.write(level, f"{level} message") pz.container(ui.console(log.entries, on_clear=on_clear), width=520, height=220) ``` ```python log = ui.Log() for level in ui.LOG_LEVELS: log.write(level, f"{level} message") pz.container(ui.console(log.entries, hidden={"info", "event"}, on_toggle_level=on_toggle), width=520, height=200) ``` ```python log = ui.Log() log.write("info", "started") log.write("error", "ValueError: bad input") pz.container(ui.console(log.entries, query="error", on_query=on_query), width=520, height=140) ``` #### Events Console has **8 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_query` | `ui.console` | `(text)` | Receives each edit of the filter. | | `on_toggle_level` | `ui.console` | `(level)` | Called with the level of the clicked toggle. | | `on_clear` | `ui.console` | `()` | Adds a Clear button. | | `on_copy` | `ui.console` | `()` | Adds a Copy button. | | `on_context` | `ui.console` | `(line)` | Called with the line right-clicked (`None` under the lines): open a menu there (copy, go to source, clear...). | | `on_open` | `ui.console` | `(line)` | Called with the line double-clicked. | | `on_source` | `ui.console` | `(source)` | Receives the source picked in the dropdown (`None` for all). | | `on_write` | `ui.Log` | `()` | Called after every write (from any thread). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Debug(pz.App): def __init__(self): self.log = ui.Log() self.log.write("info", "Started") self.log.write("error", "ValueError: bad input") self.log.on_write = lambda: pz.post("log") # a line arrived (from any thread) self.query, self.hidden = "", set() def update(self, message): pass # "log" just redraws def view(self): return ui.console(self.log.entries, query=self.query, hidden=self.hidden, on_query=lambda q: setattr(self, "query", q), # the filter on_toggle_level=lambda lvl: self.hidden.symmetric_difference_update({lvl}), on_clear=self.log.clear, # adds Clear on_copy=lambda: pz.Command.copy(self.log.text()), # adds Copy on_open=lambda entry: print("open", entry.text)) # double click ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Filter: query: str @dataclass class ToggleLevel: level: str class Debug(pz.App): log = ui.Log() query, hidden = "", frozenset() def update(self, message): match message: case Filter(query): self.query = query case ToggleLevel(level): self.hidden = self.hidden ^ {level} case "clear": self.log.clear() def view(self): return ui.console(self.log.entries, query=self.query, hidden=self.hidden, on_query=Filter, on_toggle_level=ToggleLevel, on_clear="clear") ``` **Functional:** ```python from dataclasses import dataclass LOG = ui.Log() LOG.write("info", "Started") @dataclass(frozen=True) class State: query: str = "" hidden: frozenset = frozenset() def view(state, set_state): return ui.console(LOG.entries, query=state.query, hidden=state.hidden, on_query=lambda q: set_state(query=q), on_toggle_level=lambda lvl: set_state(hidden=state.hidden ^ {lvl})) ``` #### Properties and API ##### `ui.console` ```python console( entries, *, query='', on_query=None, hidden=(), on_toggle_level=None, on_clear=None, on_copy=None, actions=(), selection=None, on_context=None, on_open=None, sources=(), source=None, on_source=None, show_source=False, placeholder=None, empty=None, font_size=12.5, id=None, theme=None, ) ``` A log view like a browser's dev tools console: a filter box, one toggle per level with its count, copy and clear, and the entries in a monospace list that keeps scrolling to the newest one. | Property | Default | Description | | --- | --- | --- | | `entries` | *required* | `ui.LogEntry` items (`log.entries`). | | `query` | `""` | Filter text. | | `hidden` | `()` | Levels not shown. | | `actions` | `()` | Extra widgets at the end of the toolbar. | | `selection` | `None` | A `ui.LogSelection`: the lines can be selected with the mouse, and a selected line with `detail` shows it below. | | `sources` | `()` | `(value, label)` pairs: adds a dropdown that shows the lines of one `source`. | | `source` | `None` | The source shown (`None` for all). | | `show_source` | `False` | Tags each line with its source. | | `placeholder` | `None` | Text of the empty filter box. | | `empty` | `None` | What shows while there are no lines. | | `font_size` | `12.5` | Size of the entries. | | `id` | `None` | Scrollable id. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_query`, `on_toggle_level`, `on_clear`, `on_copy`, `on_context`, `on_open`, `on_source` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#console) ##### `ui.Log` ```python class Log ``` The entries of a `ui.console`: thread-safe, capped at `limit`, with repeated lines folded into one. `write(level, text)` adds a line; `capture()` (or `with log:`) copies `print` output and tracebacks into it; `pipe(stream)` reads a subprocess's output in a background thread; `text()` returns everything for copying (`text(ids)` only those lines). `write` also takes the line's `source`, `detail` (a traceback) and `origin` (`(path, line)`) and returns the entry; `find(id)` looks one up. | Property | Default | Description | | --- | --- | --- | | `limit` | `5000` | Most entries kept. | Events: `on_write` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#log) ##### `ui.LogEntry` ```python @dataclass class LogEntry(level, text, time=time.time(), count=1, source='', detail='', origin=None, id=0) ``` One line of a `ui.Log`: `level`, `text`, `time`, `count` (identical lines in a row), `source`, `detail`, `origin`, its number `id`, `clock` (`HH:MM:SS`) and `line()` (the entry as plain text). | Property | Default | Description | | --- | --- | --- | | `level` | *required* | Level name. | | `text` | *required* | The line. | | `time` | `time()` | When it was written (`time.time()`). | | `count` | `1` | Identical lines in a row. | | `source` | `""` | What it comes from (`"project"`, `"agent"`...); `ui.console` can show and filter it. | | `detail` | `""` | More text shown under the line while it is selected (a traceback). | | `origin` | `None` | `(path, line)` of the code it is about. | | `id` | `0` | Its number in the log (what a `ui.LogSelection` keeps). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#logentry) ##### `ui.LogSelection` ```python class LogSelection ``` The selected lines of a `ui.console`, like in a file list: a click selects one line, Shift+click a range from the last one clicked and Ctrl+click (Cmd on macOS) adds or removes one. Keep one in your app and pass it to `ui.console(selection=...)`; `select(ids)` selects exactly those (Ctrl+A), `clear()` none, `keep(entries)` forgets lines that are gone, and `ids` are the selected entries' `id`s for `log.text(ids)`. [Full reference →](https://albakore.github.io/pyzed/reference/ui/#logselection) ##### `ui.LOG_LEVELS` The levels `ui.console` colors, in the order of its filter buttons: debug, info, event, stdout, stderr, warning, error. [Full reference →](https://albakore.github.io/pyzed/reference/ui/#log_levels) #### Related - [Terminal](https://albakore.github.io/pyzed/library/terminal/): A read-only terminal view with ANSI colors. - [Editor](https://albakore.github.io/pyzed/library/editor/): A full code editor: highlighting, folding, minimap, git markers. ### Container > Size, padding, alignment, background, border and shadow for one child. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/container/ :::tip[In plain words] A box around one thing, to give it a size, a margin, a background or a border. ::: Wraps one child to give it a size, padding and alignment, and to draw a background (color or gradient), a border, rounded corners and a shadow. `pz.center(child)` is a container that centers its child in all the available space. `pz.container` · Category: [Layout](https://albakore.github.io/pyzed/library/#layout) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#container) **Code:** ```python t = pz.theme.current() pz.row([ pz.container(ui.label("padding + bg"), padding=16, bg=t.element, radius=8), pz.container(ui.label("border"), padding=16, border_color=t.accent, border_width=2, radius=8), pz.container(ui.label("shadow", color="#ffffff"), padding=16, radius=12, gradient=(135, ["#7c3aed", "#3b82f6"]), shadow=("#00000066", (0, 6), 18)), ], spacing=16, align="center") ``` #### When to use - Whenever a widget needs a box: cards, colored areas, fixed sizes, centering. #### Usage ```python import pyzed as pz from pyzed import ui t = pz.theme.current() pz.row([ pz.container(ui.label("padding + bg"), padding=16, bg=t.element, radius=8), pz.container(ui.label("border"), padding=16, border_color=t.accent, border_width=2, radius=8), pz.container(ui.label("shadow", color="#ffffff"), padding=16, radius=12, gradient=(135, ["#7c3aed", "#3b82f6"]), shadow=("#00000066", (0, 6), 18)), ], spacing=16, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Box ```python pz.container(ui.label("padding + bg"), padding=16, bg=pz.theme.current().element, radius=8) ``` ```python pz.container(ui.label("border"), padding=16, border_color=pz.theme.current().accent, border_width=2, radius=8) ``` ```python pz.container(ui.label("pill"), padding=(6, 16), bg=pz.theme.current().element, radius=999) ``` ##### Paint ```python pz.container(ui.label("gradient", color="#ffffff"), padding=16, radius=10, gradient=(135, ["#7c3aed", "#3b82f6"])) ``` ```python pz.container(ui.label("shadow"), padding=16, radius=10, bg=pz.theme.current().elevated, shadow=("#00000066", (0, 6), 18)) ``` ##### Alignment ```python pz.container(ui.label("centered"), center=True, width=220, height=90, border_color=pz.theme.current().border, border_width=1, radius=8) ``` ```python pz.container(ui.label("bottom right"), align_x="end", align_y="end", padding=8, width=220, height=90, border_color=pz.theme.current().border, border_width=1, radius=8) ``` #### Examples ##### Centering `pz.center` (or `center=True`) centers the child in the space it gets. **Code:** ```python pz.container(pz.center(ui.label("centered")), width=360, height=120, border_color=pz.theme.current().border, border_width=1, radius=8) ``` #### Events Container has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.container` ```python container( content=None, *, padding=None, width=None, height=None, max_width=None, max_height=None, align_x=None, align_y=None, center=False, bg=None, color=None, border_color=None, border_width=0.0, radius=None, shadow=None, clip=False, gradient=None, ) ``` Wraps a child to give it size, alignment, background, border, radius and shadow. | Property | Default | Description | | --- | --- | --- | | `content` | `None` | The child (or `None` for an empty box, handy as a colored rectangle). | | `padding` | `None` | Inner padding: `8`, `(vertical, horizontal)` or `(top, right, bottom, left)`. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `max_width` | `None` | Maximum width in pixels. | | `max_height` | `None` | Maximum height in pixels. | | `align_x` | `None` | Horizontal alignment: `"start"`/`"left"`, `"center"`, `"end"`/`"right"`. | | `align_y` | `None` | Vertical alignment: `"start"`/`"top"`, `"center"`, `"end"`/`"bottom"`. | | `center` | `False` | Centers the content on both axes and fills all the space. | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `color` | `None` | Text or icon color. | | `border_color` | `None` | Border color. | | `border_width` | `0.0` | Border width in pixels. | | `radius` | `None` | Corner radius: a number or `(top_left, top_right, bottom_right, bottom_left)`. | | `shadow` | `None` | Shadow: `(color, (dx, dy), blur)`. | | `clip` | `False` | Clips content that overflows the bounds. | | `gradient` | `None` | Linear background gradient: `(angle, [colors])` or `(angle, [(position, color), ...])`. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#container) ##### `pz.center` ```python center(content, **kwargs) ``` Centers `content` in all the available space. Equivalent to `container(content, center=True)`. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `**kwargs` | — | Any `container` parameter. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#center) #### Related - [Card](https://albakore.github.io/pyzed/library/card/): A bordered surface with an optional title and actions. - [Stack](https://albakore.github.io/pyzed/library/stack/): Layers children on top of each other; `pin` places one at x, y. - [Row](https://albakore.github.io/pyzed/library/row/): Lays out children horizontally. ### Context meter > How full a model's context window is: a ring and `48k / 200k`. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/context-meter/ :::tip[In plain words] A little ring that fills up as a chat with an AI gets longer, like a fuel gauge. ::: `ui.context_meter(used, limit)` shows how full an AI model's context window is: a small ring and `48k / 200k`. It is gray below 80%, yellow from 80% and red from 95%, and its tooltip gives the exact counts. `ui.format_tokens(count)` writes a count the short way: `950`, `4.5k`, `48k`, `1.25M`. `ui.context_meter` · Category: [AI agents](https://albakore.github.io/pyzed/library/#ai-agents) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#context_meter) **Code:** ```python pz.row([ ui.context_meter(48_000, 200_000), ui.context_meter(170_000, 200_000), ui.context_meter(196_000, 200_000), ], spacing=24, align="center") ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - In the toolbar or the input box of an agent's chat, so the user sees when a conversation gets long. #### Usage ```python import pyzed as pz from pyzed import ui pz.row([ ui.context_meter(48_000, 200_000), ui.context_meter(170_000, 200_000), ui.context_meter(196_000, 200_000), ], spacing=24, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Level Drawn as the pointer shows it: tooltips only open on hover. ```python ui.context_meter(48_000, 200_000) ``` ```python ui.context_meter(170_000, 200_000) ``` ```python ui.context_meter(196_000, 200_000) ``` ```python ui.context_meter(48_000, 200_000) ``` ##### Short counts `ui.format_tokens` returns the text the meter shows, for your own labels. ```python ui.label(ui.format_tokens(950), mono=True) ``` ```python ui.label(ui.format_tokens(4_500), mono=True) ``` ```python ui.label(ui.format_tokens(48_000), mono=True) ``` ```python ui.label(ui.format_tokens(1_250_000), mono=True) ``` #### Events Context meter has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.context_meter` ```python context_meter(used, limit, *, theme=None) ``` How full a model's context window is, like Zed's token counter: a small ring and `48k / 200k`, yellow past 80% and red past 95%. | Property | Default | Description | | --- | --- | --- | | `used` | *required* | Tokens in use. | | `limit` | *required* | The model's window. | | `theme` | `None` | Theme. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#context_meter) ##### `ui.format_tokens` ```python format_tokens(count) ``` A short token count: `950`, `4.5k`, `48k`, `1.25M`. | Property | Default | Description | | --- | --- | --- | | `count` | *required* | Tokens. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#format_tokens) #### Related - [Donut](https://albakore.github.io/pyzed/library/donut/): A donut chart with a label in the middle. - [Progress](https://albakore.github.io/pyzed/library/progress/): A thin progress bar in a semantic color. - [Tool call](https://albakore.github.io/pyzed/library/tool-call/): One step of an AI agent: what it did, its result, and Allow or Reject. ### Count badge > A round counter that shows 99+ above its max. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/count-badge/ :::tip[In plain words] A little round number, like the count of unread messages on an app icon. ::: A round counter for notifications or problems. Above `max` it shows `99+`. `ui.count_badge` · Category: [Feedback](https://albakore.github.io/pyzed/library/#feedback) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#count_badge) **Code:** ```python pz.row([ ui.count_badge(3), ui.count_badge(42, tint="success"), ui.count_badge(120, tint="error"), pz.row([ui.icon_button("bell", on_press), ui.count_badge(7)], spacing=2, align="center"), ], spacing=16, align="center") ``` #### When to use - Next to an icon or tab to show how many unread items or errors there are. - For text statuses use a [Badge](https://albakore.github.io/pyzed/library/badge/). #### Usage ```python import pyzed as pz from pyzed import ui pz.row([ ui.count_badge(3), ui.count_badge(42, tint="success"), ui.count_badge(120, tint="error"), pz.row([ui.icon_button("bell", on_press), ui.count_badge(7)], spacing=2, align="center"), ], spacing=16, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Count Above `max` it shows `max+`. ```python ui.count_badge(3) ``` ```python ui.count_badge(42) ``` ```python ui.count_badge(120) ``` ```python ui.count_badge(12, max=9) ``` ##### Tint ```python ui.count_badge(5, tint="success") ``` ```python ui.count_badge(5, tint="warning") ``` ```python ui.count_badge(5, tint="error") ``` ##### Next to an icon ```python pz.row([ui.icon_button("bell", on_press), ui.count_badge(7)], spacing=2, align="center") ``` ##### States and events With `show_zero=False` it draws nothing at 0 but keeps its place in the layout. ```python pz.row([ui.icon_button("bell", on_press), ui.count_badge(0, show_zero=False)], align="center") ``` #### Events Count badge has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.count_badge` ```python count_badge(count, *, tint='accent', max=99, show_zero=True, theme=None) ``` A round counter (notifications, problems…). Shows `99+` above `max`. | Property | Default | Description | | --- | --- | --- | | `count` | *required* | The number. | | `tint` | `"accent"` | Semantic color: `"accent"`, `"error"`, `"warning"`, `"success"`, `"info"` or a token. | | `max` | `99` | Maximum before showing `N+`. | | `show_zero` | `True` | With `False`, a count of 0 draws nothing. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#count_badge) #### Related - [Badge](https://albakore.github.io/pyzed/library/badge/): A small pill for statuses, versions and counters. - [Indicator](https://albakore.github.io/pyzed/library/indicator/): A colored dot for status, presence or unsaved changes. - [Status bar](https://albakore.github.io/pyzed/library/status-bar/): The bottom bar: diagnostics, cursor position, language. ### Date picker > A date field with a calendar that drops down, in the format you choose. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/date-picker/ :::tip[In plain words] A box for a date. Type it, or press the little calendar and click a day. ::: `ui.DatePicker` is a text field for one date. The calendar button (or Alt+↓) opens a [Calendar](https://albakore.github.io/pyzed/library/calendar/) under it, and the user can also type the date: it is read with `format` when they press Enter or leave the field. With the focus in the field, ↑ and ↓ move one day and Page Up/Page Down one month, without opening anything. `on_change` receives a `datetime.date` (or `None` when the field is cleared) in `event.value`. `ui.DatePicker` · Category: [Dates and times](https://albakore.github.io/pyzed/library/#dates-and-times) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#datepicker) **Code:** ```python pz.container( ui.DatePicker(value="2026-10-22", format="DD/MM/YYYY", on_change=on_change), width=220, height=330, align_y="start") ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For birthdays, due dates, bookings and any form field that holds a date. - `format` takes tokens (`DD/MM/YYYY`, `MMM D, YYYY`, `dddd D MMMM`) or a `strftime` pattern (`%d.%m.%Y`). Month and day names follow the app's language. - `min`, `max` and `disabled_dates` (dates, `"weekend"` or day names) turn days off. - For two dates (from–to), use [Date range picker](https://albakore.github.io/pyzed/library/date-range-picker/). #### Usage ```python import pyzed as pz from pyzed import ui import datetime class Booking(pz.App): def __init__(self): self.day = datetime.date.today() def view(self): return pz.column([ ui.field("Check-in", ui.DatePicker(value=self.day, format="ddd D MMM YYYY", min=datetime.date.today(), disabled_dates=["sunday"], on_change=lambda e: setattr(self, "day", e.value))), ui.label(f"Booked for {ui.format_date(self.day, 'dddd D MMMM')}"), ], spacing=12, width=320) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Format Tokens: `YYYY` `YY`, `MMMM` `MMM` `MM` `M`, `DD` `D`, `dddd` `ddd`; `[text]` is copied as is. ```python ui.DatePicker(value="2026-10-22", on_change=on_change) ``` ```python ui.DatePicker(value="2026-10-22", format="DD/MM/YYYY", on_change=on_change) ``` ```python ui.DatePicker(value="2026-10-22", format="MMM D, YYYY", on_change=on_change) ``` ```python ui.DatePicker(value="2026-10-22", format="ddd D MMM", on_change=on_change) ``` ##### States ```python ui.DatePicker(placeholder="Pick a date", on_change=on_change) ``` ```python ui.DatePicker(value="2026-10-22", invalid=True, on_change=on_change) ``` ```python ui.DatePicker(value="2026-10-22", disabled=True, on_change=on_change) ``` ```python ui.DatePicker(value="2026-10-22", on_change=on_change) ``` #### Examples ##### Formats `ui.format_date` and `ui.parse_date` use the same tokens as the field, for your own labels. **Code:** ```python pz.column([ ui.label(ui.format_date("2026-10-22", "DD/MM/YYYY"), mono=True), ui.label(ui.format_date("2026-10-22", "MMM D, YYYY"), mono=True), ui.label(ui.format_date("2026-10-22", "dddd, D MMMM YYYY"), mono=True), ui.label(ui.format_date("2026-10-22", "[week of] D/M/YY"), mono=True), ], spacing=6) ``` #### Events Date picker has **4 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_change` | `ui.DatePicker` | `(event)` | Receives `event.value`: a `datetime.date` or `None`. | | `on_open` | `ui.DatePicker` | `(event)` | The calendar opened. | | `on_close` | `ui.DatePicker` | `(event)` | The calendar closed. | | `on_dismiss` | `pz.popup` | `()` | Message or callable sent on a press outside or Escape. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python import datetime class Booking(pz.App): def __init__(self): self.day = datetime.date(2026, 10, 22) def changed(self, event): # on_change: event.value is a datetime.date (or None) self.day = event.value def view(self): return pz.column([ ui.DatePicker(value=self.day, format="DD/MM/YYYY", on_change=self.changed), ui.label(ui.format_date(self.day, "dddd D MMMM") or "No date"), ], spacing=8, width=240) ``` **Declarative:** ```python import datetime from dataclasses import dataclass @dataclass class Picked: day: datetime.date class Booking(pz.App): day = datetime.date(2026, 10, 22) def update(self, message): match message: case Picked(day): self.day = day def view(self): # DatePicker is a pz.Component: its handler gets a pz.Event return ui.DatePicker(value=self.day, on_change=lambda e: Picked(e.value)) ``` **Functional:** ```python import datetime from dataclasses import dataclass @dataclass(frozen=True) class State: day: datetime.date = datetime.date(2026, 10, 22) def view(state, set_state): return pz.column([ ui.DatePicker(value=state.day, format="MMM D, YYYY", on_change=lambda e: set_state(day=e.value)), ui.label(f"Week {state.day.isocalendar().week}" if state.day else "No date"), ], spacing=8, width=240) ``` #### Tips :::tip The calendar opens in a `pz.popup`, a layer drawn over the window: it is never clipped by a scrollable or a small container, flips above the field when there is no room below and closes with Escape or a click outside. ::: #### Properties and API ##### `ui.DatePicker` ```python class DatePicker ``` A component: a date field that opens a calendar below it, in a popup that panels never cut off. It can be typed in `format` (Enter or leaving the field reads it); once clicked, ↑/↓ move the date a day and Page Up/Down a month without opening anything, Alt+↓ opens the calendar and Escape closes it. See the [Date picker](https://albakore.github.io/pyzed/library/date-picker/) page. | Property | Default | Description | | --- | --- | --- | | `value` | `None` | The date (`datetime.date`, ISO text or `None`). | | `format` | `"YYYY-MM-DD"` | How it is written: `"DD/MM/YYYY"`, `"MMM D, YYYY"`... (see `format_date`). | | `placeholder` | `""` | Hint while empty (default: the format). | | `min` | `None` | The earliest date. | | `max` | `None` | The latest date. | | `disabled_dates` | `()` | Days that cannot be picked (as in `Calendar`). | | `first_weekday` | `"monday"` | `"monday"`, `"sunday"` or `"saturday"`. | | `week_numbers` | `False` | Shows week numbers in the calendar. | | `clearable` | `True` | Shows an x that empties it. | | `today_button` | `True` | Adds a Today link to the calendar. | | `disabled` | `False` | Greys it out. | | `invalid` | `False` | Paints the border in the error color. | Events: `on_change`, `on_open`, `on_close` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#datepicker) ##### `ui.format_date` ```python format_date(value, fmt='YYYY-MM-DD', *, language=None) ``` Writes a date with a pattern of tokens: `YYYY` 2026, `YY` 26, `MMMM` October, `MMM` Oct, `MM` 10, `M` 10, `DD` 05, `D` 5, `dddd` Monday, `ddd` Mon, `HH`/`hh` hours, `mm` minutes, `ss` seconds, `A` AM/PM and `[text]` kept as is. A pattern with `%` is a `strftime` one. Month and day names follow the language of `pyzed.i18n`. | Property | Default | Description | | --- | --- | --- | | `value` | *required* | A date, a datetime, ISO text or `None` (gives `""`). | | `fmt` | `"YYYY-MM-DD"` | The pattern. | | `language` | `None` | A language for the names instead of the current one. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#format_date) ##### `ui.parse_date` ```python parse_date(text, fmt='YYYY-MM-DD', *, language=None) ``` Reads a date written with a pattern of `format_date` (month names in the current language or English); ISO `YYYY-MM-DD` always works. Returns `None` when the text is not a date. | Property | Default | Description | | --- | --- | --- | | `text` | *required* | The text. | | `fmt` | `"YYYY-MM-DD"` | The pattern. | | `language` | `None` | The language of the names. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#parse_date) ##### `pz.popup` ```python popup(base, content=None, *, on_dismiss=None, side='bottom', align='start', gap=4.0) ``` Shows `content` over everything else next to `base`, like the menu of a drop-down: it is not cut off by the panels `base` sits in, flips to the other side when it does not fit and stays inside the window. A press outside it (and outside `base`) or Escape calls `on_dismiss`. With `content=None` only `base` is shown. The date pickers open their calendars with it. | Property | Default | Description | | --- | --- | --- | | `base` | *required* | The widget it belongs to (a field, a button). | | `content` | `None` | What opens (a panel, a menu), or `None` while closed. | | `side` | `"bottom"` | `"bottom"`, `"top"`, `"right"` or `"left"` of `base`. | | `align` | `"start"` | `"start"`, `"center"` or `"end"`: how it lines up with `base`. | | `gap` | `4.0` | Space between `base` and the content. | Events: `on_dismiss` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#popup) #### Related - [Calendar](https://albakore.github.io/pyzed/library/calendar/): A month grid to pick a day, a range or several days, always on screen. - [Date range picker](https://albakore.github.io/pyzed/library/date-range-picker/): Two dates in one field, with two months side by side and quick ranges. - [Time picker](https://albakore.github.io/pyzed/library/time-picker/): A time field with columns of hours and minutes, in 24 or 12 hours. - [Input](https://albakore.github.io/pyzed/library/input/): A controlled text field with icon, placeholder and password mode. ### Date range picker > Two dates in one field, with two months side by side and quick ranges. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/date-range-picker/ :::tip[In plain words] A box for two dates, from and to. You click where the period starts and where it ends. ::: `ui.DateRangePicker` holds a start and an end date. Its popup shows two months: the first click picks the start, the pointer previews the range and the second click picks the end (in any order). The column on the left has quick ranges (today, last 7 days, this week, this month, last month...). `on_change` receives `(start, end)` as two `datetime.date`. `ui.DateRangePicker` · Category: [Dates and times](https://albakore.github.io/pyzed/library/#dates-and-times) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#daterangepicker) **Code:** ```python pz.container( ui.DateRangePicker(value=("2026-10-05", "2026-10-14"), format="DD/MM/YYYY", on_change=on_change), width=260, height=330, align_y="start") ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For reports, filters, stays and anything that spans days. - `months=1` shows a single month and `presets=False` hides the quick ranges. - The field can be typed too: two dates in `format` with any separator. #### Usage ```python import pyzed as pz from pyzed import ui class Report(pz.App): def __init__(self): self.period = (None, None) def view(self): start, end = self.period days = (end - start).days + 1 if start and end else 0 return pz.column([ ui.DateRangePicker(value=self.period, format="MMM D, YYYY", on_change=lambda e: setattr(self, "period", e.value)), ui.label(f"{days} days selected", color="text_muted"), ], spacing=8, width=300) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Popup ```python ui.DateRangePicker(value=("2026-10-05", "2026-10-14"), on_change=on_change) ``` ```python ui.DateRangePicker(months=1, presets=False, on_change=on_change) ``` #### Events Date range picker has **3 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Handler gets | When | | --- | --- | --- | | `on_change` | `(event)` | Receives `event.value`: `(start, end)`. | | `on_open` | `(event)` | The calendar opened. | | `on_close` | `(event)` | The calendar closed. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Report(pz.App): def __init__(self): self.period = ("2026-10-05", "2026-10-14") def changed(self, event): # on_change: event.value is (start, end) self.period = event.value def view(self): start, end = self.period return pz.column([ ui.DateRangePicker(value=self.period, on_change=self.changed), ui.label(f"From {ui.format_date(start, 'D MMM')} to {ui.format_date(end, 'D MMM')}"), ], spacing=8, width=280) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Period: days: tuple class Report(pz.App): period = (None, None) def update(self, message): match message: case Period(days): self.period = days def view(self): return ui.DateRangePicker(value=self.period, on_change=lambda e: Period(e.value)) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: period: tuple = (None, None) def view(state, set_state): return ui.DateRangePicker(value=state.period, months=1, presets=False, on_change=lambda e: set_state(period=e.value)) ``` #### Properties and API ##### `ui.DateRangePicker` ```python class DateRangePicker ``` A component: a field for a start and an end date, with two months and quick ranges (Today, Last 7 days, This month...) in its popup. Typed text is two dates separated by `separator`. See the [Date range picker](https://albakore.github.io/pyzed/library/date-range-picker/) page. | Property | Default | Description | | --- | --- | --- | | `value` | `None` | `(start, end)`: dates, ISO text or `None`. | | `format` | `"YYYY-MM-DD"` | How each date is written. | | `separator` | `" – "` | Text between the two dates. | | `placeholder` | `""` | Hint while empty. | | `min` | `None` | The earliest date. | | `max` | `None` | The latest date. | | `disabled_dates` | `()` | Days that cannot be picked. | | `first_weekday` | `"monday"` | `"monday"`, `"sunday"` or `"saturday"`. | | `months` | `2` | Months shown side by side. | | `presets` | `True` | Shows the quick ranges. | | `clearable` | `True` | Shows an x that empties it. | | `disabled` | `False` | Greys it out. | | `invalid` | `False` | Paints the border in the error color. | Events: `on_change`, `on_open`, `on_close` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#daterangepicker) #### Related - [Date picker](https://albakore.github.io/pyzed/library/date-picker/): A date field with a calendar that drops down, in the format you choose. - [Calendar](https://albakore.github.io/pyzed/library/calendar/): A month grid to pick a day, a range or several days, always on screen. ### Dialog layer > Centers a dialog over your view with a dimmed backdrop. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/dialog-layer/ :::tip[In plain words] Darkens the app and shows a dialog in the middle, so the question can't be missed. ::: Shows a dialog centered over `base` with a dimmed backdrop; clicking the backdrop calls `on_dismiss`. With `dialog=None` it returns `base` unchanged, so keep which dialog is open in your state and always wrap the view with it. `ui.dialog_layer` · Category: [Dialogs](https://albakore.github.io/pyzed/library/#dialogs) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#dialog_layer) **Code:** ```python ui.dialog_layer( main_view(), ui.confirm("Delete notes.py? This can't be undone.", on_delete, on_cancel, title="Delete file", danger=True, width=340), on_dismiss=on_cancel, ) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - Around your whole view, to show any of the dialogs on this page or a `ui.modal`. #### Usage ```python import pyzed as pz from pyzed import ui class Files(pz.App): def __init__(self): self.asking = False def close(self): self.asking = False def view(self): dialog = None if self.asking: dialog = ui.confirm("Delete main.py?", self.delete, self.close, title="Delete file", danger=True) return ui.dialog_layer(self.main_view(), dialog, on_dismiss=self.close) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Dialog ```python ui.dialog_layer(main_view(), ui.alert("Export finished.", on_close, kind="success", width=280)) ``` ```python ui.dialog_layer(main_view(), ui.modal(ui.muted("Any content."), title="Modal", on_close=on_close, width=280), on_dismiss=on_close) ``` ```python ui.dialog_layer(main_view(), None) ``` #### Events Dialog layer has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_dismiss` | `()` | Sent when the backdrop is clicked. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Files(pz.App): def __init__(self): self.asking = True def close(self): self.asking = False def view(self): dialog = ui.confirm("Delete main.py?", self.close, self.close, danger=True) if self.asking else None return ui.dialog_layer(main_view(), dialog, on_dismiss=self.close) # click on the backdrop ``` **Declarative:** ```python class Files(pz.App): asking = True def update(self, message): if message in ("delete", "cancel"): self.asking = False def view(self): dialog = ui.confirm("Delete main.py?", "delete", "cancel", danger=True) if self.asking else None return ui.dialog_layer(main_view(), dialog, on_dismiss="cancel") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: asking: bool = True def view(state, set_state): close = lambda: set_state(asking=False) dialog = ui.confirm("Delete main.py?", close, close, danger=True) if state.asking else None return ui.dialog_layer(main_view(), dialog, on_dismiss=close) ``` #### Tips :::tip Button labels (OK, Cancel, Save…) are translated with [`pyzed.i18n`](https://albakore.github.io/pyzed/guides/i18n/). ::: #### Properties and API ##### `ui.dialog_layer` ```python dialog_layer(base, dialog=None, *, on_dismiss=None, theme=None) ``` Shows a dialog centered over `base` with a dimmed backdrop. With `dialog=None` it returns `base` unchanged, so it can always wrap the view. See [Dialogs](https://albakore.github.io/pyzed/guides/i18n/#dialogs). | Property | Default | Description | | --- | --- | --- | | `base` | *required* | The UI underneath. | | `dialog` | `None` | A dialog from the functions below, or `ui.modal`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_dismiss` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#dialog_layer) #### Related - [Alert](https://albakore.github.io/pyzed/library/alert/): A message with one button. - [Confirm](https://albakore.github.io/pyzed/library/confirm/): A yes/no question, red for destructive actions. - [Prompt](https://albakore.github.io/pyzed/library/prompt/): Asks for a line of text. - [Modal](https://albakore.github.io/pyzed/library/modal/): A dialog surface with title, content and footer buttons. ### Diff stat > `+12 −3` with GitHub-style blocks. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/diff-stat/ :::tip[In plain words] How many lines were added (green) and removed (red) in a change. ::: Lines added and removed, with a row of green and red blocks, as in the git panel of a code editor. `ui.diff_stat` · Category: [Data](https://albakore.github.io/pyzed/library/#data) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#diff_stat) **Code:** ```python pz.column([ pz.row([ui.label("render.rs", mono=True), pz.hspace(), ui.diff_stat(42, 9)], align="center"), pz.row([ui.label("app.py", mono=True), pz.hspace(), ui.diff_stat(3, 27)], align="center"), pz.row([ui.label("README.md", mono=True), pz.hspace(), ui.diff_stat(12, 0)], align="center"), ], spacing=10, width=320) ``` #### When to use - Next to a file, commit or pull request in a list of changes. #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ pz.row([ui.label("render.rs", mono=True), pz.hspace(), ui.diff_stat(42, 9)], align="center"), pz.row([ui.label("app.py", mono=True), pz.hspace(), ui.diff_stat(3, 27)], align="center"), pz.row([ui.label("README.md", mono=True), pz.hspace(), ui.diff_stat(12, 0)], align="center"), ], spacing=10, width=320) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python ui.diff_stat(42, 3) ``` ```python ui.diff_stat(2, 57) ``` ```python ui.diff_stat(12, 0) ``` ```python ui.diff_stat(120, 40, blocks=10) ``` #### Events Diff stat has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.diff_stat` ```python diff_stat(added, removed, *, blocks=5, theme=None) ``` `+12 −3` with GitHub-style colored blocks. | Property | Default | Description | | --- | --- | --- | | `added` | *required* | Lines added. | | `removed` | *required* | Lines removed. | | `blocks` | `5` | Number of blocks. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#diff_stat) #### Related - [Badge](https://albakore.github.io/pyzed/library/badge/): A small pill for statuses, versions and counters. - [Tree](https://albakore.github.io/pyzed/library/tree/): A collapsible file tree with icons and git colors. ### Diff view > An edit as colored lines: added in green, removed in red. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/diff-view/ :::tip[In plain words] Shows what changed in a file: new lines in green, deleted lines in red. ::: `ui.diff_view(diff)` shows an edit: the file's name, then the lines that changed (added in green, removed in red) with two lines of context around each change; changes far apart are split by `⋯`. `diff` is a dict with `path`, `old` and `new`, the whole texts before and after, and `max_lines` limits how many lines show before `… N more lines`. It is what a [Tool call](https://albakore.github.io/pyzed/library/tool-call/) shows for the edits it made. `ui.diff_view` · Category: [AI agents](https://albakore.github.io/pyzed/library/#ai-agents) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#diff_view) **Code:** ```python old = "def save(path):\n data = load()\n write(path, data)\n return True\n" new = "def save(path, data):\n write(path, data)\n log(path)\n return True\n" pz.container(ui.diff_view({"path": "app/storage.py", "old": old, "new": new}), width=420) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - To show what an agent or a tool changed in a file. - To review a change before saving it, next to Keep and Reject buttons. - For the counts alone (`+12 −3`), use [Diff stat](https://albakore.github.io/pyzed/library/diff-stat/). #### Usage ```python import pyzed as pz from pyzed import ui old = "def save(path):\n data = load()\n write(path, data)\n return True\n" new = "def save(path, data):\n write(path, data)\n log(path)\n return True\n" pz.container(ui.diff_view({"path": "app/storage.py", "old": old, "new": new}), width=420) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content Two lines of context surround each change; changes further apart are split by `⋯`. ```python pz.container(ui.diff_view({"path": "app.py", "old": "x = 1\ny = 2\n", "new": "x = 10\ny = 2\n"}), width=300) ``` ```python pz.container(ui.diff_view({"path": "main.py", "old": "", "new": "import pyzed as pz\n\npz.run(App)\n"}), width=300) ``` ```python pz.container(ui.diff_view({"path": "todo.txt", "old": "milk\neggs\nbread\n", "new": "milk\n"}), width=300) ``` ```python old = "".join(f"line {i}\n" for i in range(1, 13)) new = old.replace("line 2\n", "line two\n").replace("line 11\n", "") pz.container(ui.diff_view({"path": "notes.txt", "old": old, "new": new}), width=300) ``` ```python new = "".join(f"item {i}\n" for i in range(1, 11)) pz.container(ui.diff_view({"path": "list.txt", "old": "", "new": new}, max_lines=4), width=300) ``` #### Events Diff view has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.diff_view` ```python diff_view(diff, *, theme=None, max_lines=120) ``` An edit as Zed shows it in a thread: the file's name, then the changed lines (green added, red removed) with a few lines around them. | Property | Default | Description | | --- | --- | --- | | `diff` | *required* | A dict with `path`, `old` and `new` (the texts before and after). | | `theme` | `None` | Theme. | | `max_lines` | `120` | Lines shown before `… N more lines`. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#diff_view) #### Related - [Tool call](https://albakore.github.io/pyzed/library/tool-call/): One step of an AI agent: what it did, its result, and Allow or Reject. - [Diff stat](https://albakore.github.io/pyzed/library/diff-stat/): `+12 −3` with GitHub-style blocks. - [Edits bar](https://albakore.github.io/pyzed/library/edits-bar/): The files an agent changed, with Keep all and Reject all. ### Disclosure > One collapsible section with an arrow. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/disclosure/ :::tip[In plain words] A section with a little arrow that shows or hides extra details. ::: A header with an arrow that shows or hides `content`. You own the open state: change it in `on_toggle`. `ui.disclosure` · Category: [Lists and menus](https://albakore.github.io/pyzed/library/#lists-and-menus) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#disclosure) **Code:** ```python pz.column([ ui.disclosure("Advanced options", ui.muted("Shown while the section is open."), open=True, on_toggle=on_toggle), ui.disclosure("Environment variables", ui.muted("Hidden"), open=False, on_toggle=on_toggle, end=ui.badge("3")), ], spacing=10, width=380) ``` #### When to use - To hide advanced options or details until they are needed. #### Usage ```python import pyzed as pz from pyzed import ui class Form(pz.App): def __init__(self): self.advanced = False def view(self): return ui.disclosure("Advanced options", self.advanced_options(), open=self.advanced, on_toggle=lambda: setattr(self, "advanced", not self.advanced)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### State ```python pz.container(ui.disclosure("Advanced options", ui.muted("…"), open=False, on_toggle=on_toggle), width=300) ``` ```python pz.container(ui.disclosure("Advanced options", ui.muted("Shown while open."), open=True, on_toggle=on_toggle), width=300) ``` ```python pz.container(ui.disclosure("Environment", ui.muted("…"), open=False, on_toggle=on_toggle, end=ui.badge("3")), width=300) ``` #### Events Disclosure has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_toggle` | `()` | Message or callable when the header is clicked. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Form(pz.App): def __init__(self): self.advanced = False def view(self): return ui.disclosure("Advanced options", ui.muted("Proxy, timeouts…"), open=self.advanced, on_toggle=lambda: setattr(self, "advanced", not self.advanced)) # no argument ``` **Declarative:** ```python class Form(pz.App): advanced = False def update(self, message): if message == "toggle advanced": self.advanced = not self.advanced def view(self): return ui.disclosure("Advanced options", ui.muted("…"), open=self.advanced, on_toggle="toggle advanced") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: advanced: bool = False def view(state, set_state): return ui.disclosure("Advanced options", ui.muted("…"), open=state.advanced, on_toggle=lambda: set_state(advanced=not state.advanced)) ``` #### Properties and API ##### `ui.disclosure` ```python disclosure(title, content, *, open, on_toggle=None, end=None, theme=None) ``` A collapsible section: a header with an arrow that shows or hides `content`. You own the open state: change it in `on_toggle`. | Property | Default | Description | | --- | --- | --- | | `title` | *required* | Title (text or widget). | | `content` | *required* | Content. | | `open` | *required* | Whether it is open. | | `end` | `None` | Widgets at the end (right). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_toggle` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#disclosure) #### Related - [Accordion](https://albakore.github.io/pyzed/library/accordion/): Stacked collapsible sections, like the panels of a settings screen. - [Card](https://albakore.github.io/pyzed/library/card/): A bordered surface with an optional title and actions. ### Divider > A thin line in the theme's border color. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/divider/ :::tip[In plain words] A thin line that separates groups of things. ::: A one-pixel line in the theme's border color, horizontal by default (`vertical=True` for a vertical one). `pz.rule` is the base version with your own `color` and `thickness`. `ui.divider` · Category: [Display](https://albakore.github.io/pyzed/library/#display) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#divider) **Code:** ```python pz.column([ ui.label("Account"), ui.divider(), pz.row([ui.label("Edit"), ui.divider(vertical=True), ui.label("View"), ui.divider(vertical=True), ui.label("Help")], spacing=12, height=20), ui.divider(), ui.muted("Sign out"), ], spacing=10, width=300) ``` #### When to use - To separate groups in a column or items in a toolbar. - Prefer spacing first; add a divider when groups really need a visual break. #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ ui.label("Account"), ui.divider(), pz.row([ui.label("Edit"), ui.divider(vertical=True), ui.label("View"), ui.divider(vertical=True), ui.label("Help")], spacing=12, height=20), ui.divider(), ui.muted("Sign out"), ], spacing=10, width=300) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Direction ```python pz.column([ui.label("Account"), ui.divider(), ui.label("Sign out")], spacing=8, width=220) ``` ```python pz.row([ui.label("Edit"), ui.divider(vertical=True), ui.label("View")], spacing=10, height=18) ``` ##### Color ```python pz.container(ui.divider(color="accent"), width=220) ``` ```python pz.container(pz.rule(color="#e5c07b", thickness=3), width=220) ``` ##### States and events ```python pz.container(ui.divider(label="or"), width=300) ``` ```python pz.column([ui.label("Above"), ui.divider(spacing=12), ui.label("Below")], width=300) ``` #### Events Divider has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.divider` ```python divider(*, vertical=False, color=None, label=None, spacing=0, theme=None) ``` A divider line in the theme color. | Property | Default | Description | | --- | --- | --- | | `vertical` | `False` | Vertical instead of horizontal. | | `color` | `None` | Text or icon color. | | `label` | `None` | Muted text in the middle of a horizontal line (`"or"`, a date…). | | `spacing` | `0` | Space on both sides of the line. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#divider) ##### `pz.rule` ```python rule(*, vertical=False, thickness=1.0, color=None) ``` A horizontal (or vertical) divider line. | Property | Default | Description | | --- | --- | --- | | `vertical` | `False` | Vertical line instead of horizontal. | | `thickness` | `1.0` | Thickness in pixels. | | `color` | `None` | Text or icon color. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#rule) #### Related - [Card](https://albakore.github.io/pyzed/library/card/): A bordered surface with an optional title and actions. - [Toolbar](https://albakore.github.io/pyzed/library/toolbar/): The bar under the tabs: breadcrumbs and buffer actions. ### Donut > A donut chart with a label in the middle. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/donut/ :::tip[In plain words] A ring cut into colored slices that shows the parts of a whole. ::: A donut chart of `values`, with a `label` in the center. `colors` overrides the theme's palette. `ui.donut` · Category: [Data](https://albakore.github.io/pyzed/library/#data) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#donut) **Code:** ```python pz.row([ ui.donut([60, 25, 15], label="60%"), ui.donut([45, 35, 20], colors=["#e5c07b", "#c678dd", "#56b6c2"], size=120, thickness=20, label="3"), ], spacing=32, align="center") ``` #### When to use - To show the parts of a whole (disk usage, languages of a project) with three or four slices. #### Usage ```python import pyzed as pz from pyzed import ui pz.row([ ui.donut([60, 25, 15], label="60%"), ui.donut([45, 35, 20], colors=["#e5c07b", "#c678dd", "#56b6c2"], size=120, thickness=20, label="3"), ], spacing=32, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python ui.donut([60, 25, 15], label="60%") ``` ```python ui.donut([45, 35, 20], colors=["#e5c07b", "#c678dd", "#56b6c2"], label="3") ``` ```python ui.donut([70, 30], thickness=6, label="70%") ``` ```python ui.donut([40, 30, 20, 10], size=140, thickness=24) ``` ```python ui.donut([82, 18], size=110, label="82%") ``` #### Events Donut has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.donut` ```python donut(values, *, colors=None, size=96, thickness=14, label=None, theme=None) ``` A donut chart; `label` is drawn in the center. | Property | Default | Description | | --- | --- | --- | | `values` | *required* | Values. | | `colors` | `None` | Colors (defaults to the theme's). | | `size` | `96` | Size. | | `thickness` | `14` | Ring thickness. | | `label` | `None` | Center text. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#donut) #### Related - [Bar chart](https://albakore.github.io/pyzed/library/bar-chart/): A vertical bar chart with labels. - [Stat](https://albakore.github.io/pyzed/library/stat/): A dashboard number with change and sparkline. ### Drop zone > An area that takes files dragged from the desktop or the file manager. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/drop-zone/ :::tip[In plain words] A dashed area where you drag files from your desktop and let go to add them. ::: `ui.DropZone` lights up when files are dragged over the window and receives them when they are dropped: `on_drop` gets each path and `on_files` the whole list. `accept` limits the types (`["png", "jpg"]`, `["*.tar.gz"]`, `["folder"]`) and files of other types go to `on_reject`. With `browse=True` (the default) a click opens the file dialog too. When a window has several zones, the one under the pointer gets the files, or else the one that accepts their type. `ui.DropZone` · Category: [System](https://albakore.github.io/pyzed/library/#system) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#dropzone) **Code:** ```python pz.row([ ui.DropZone(text="Drop images here", hint="PNG or JPG, up to 10 MB", accept=["png", "jpg"], on_files=on_files), ui.DropZone(icon_name="file-spreadsheet", text="Import a CSV", accept=["csv"], multiple=False, show_files=True, files=["~/data/sales-2026.csv"], on_files=on_files), ], spacing=16, width=600) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For importing images, documents or data files, and attaching files to a message. - `show_files=True` lists what was dropped, with a button to remove each one; `multiple=False` keeps only the last file. - Dropped files also reach `on_file_drop(path)` of the window, for apps that don't need a zone. #### Usage ```python import pyzed as pz from pyzed import ui class Gallery(pz.App): def __init__(self): self.images = [] def view(self): return pz.column([ ui.DropZone(text="Drop photos", accept=["png", "jpg", "webp"], on_files=lambda e: setattr(self, "images", list(e.value))), pz.row([pz.image(path, width=96, height=96) for path in self.images], spacing=8), ], spacing=12) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### States ```python ui.DropZone(text="Drop files here", on_files=on_files) ``` ```python ui.DropZone(text="Drop files here", on_files=on_files) ``` ```python ui.DropZone(text="Drop images here", accept=["png", "jpg"], on_files=on_files) ``` ```python ui.DropZone(text="Drop files here", disabled=True, on_files=on_files) ``` ##### Files ```python ui.DropZone(text="Attach files", show_files=True, files=["~/docs/brief.pdf", "~/img/cover.png"], on_files=on_files) ``` ```python ui.DropZone(icon_name="image", text="Drag a picture", hint="Only by dragging", browse=False, on_files=on_files) ``` #### Events Drop zone has **5 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Handler gets | When | | --- | --- | --- | | `on_drop` | `(event)` | Receives `event.value`: one dropped path (once per file). | | `on_files` | `(event)` | Receives `event.value`: the list of files. | | `on_reject` | `(event)` | Receives a path it does not accept. | | `on_enter` | `(event)` | Files are dragged over the window. | | `on_leave` | `(event)` | The drag left without dropping. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Attach(pz.App): def __init__(self): self.files = [] def received(self, event): # on_files: event.value is every file so far self.files = list(event.value) def view(self): return pz.column([ ui.DropZone(text="Drop files to attach", on_files=self.received), ui.label(f"{len(self.files)} files"), ], spacing=8, width=320) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Dropped: path: str class Attach(pz.App): files = () def update(self, message): match message: case Dropped(path): self.files = (*self.files, path) def view(self): # on_drop runs once per file return ui.DropZone(accept=["png", "jpg"], on_drop=lambda e: Dropped(e.value)) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: rejected: str = "" def view(state, set_state): return pz.column([ ui.DropZone(text="Drop a CSV", accept=["csv"], multiple=False, on_reject=lambda e: set_state(rejected=e.value)), ui.label(f"Not a CSV: {state.rejected}" if state.rejected else ""), ], spacing=8, width=320) ``` #### Tips :::tip Pyzed Design has a Drop zone in the System section of the toolbox, next to the non-visual helpers of the operating system (system information, launcher, network and battery monitors). ::: #### Properties and API ##### `ui.DropZone` ```python class DropZone ``` A component that takes files dragged from the system's file manager and dropped on the window, and opens the file dialog on a click. It lights up while files are dragged over the window and keeps the dropped paths in `files`. The window's `on_file_drop` hook hands each file to the zone under the pointer, else to one whose `accept` lists its type. See the [Drop zone](https://albakore.github.io/pyzed/library/drop-zone/) page. | Property | Default | Description | | --- | --- | --- | | `text` | `""` | The main text (default: Drop files here). | | `hint` | `""` | The line under it. | | `icon_name` | `"upload"` | Its icon. | | `accept` | `()` | Extensions (`["png", "jpg"]`), patterns (`"*.tar.gz"`) or `"folder"`; empty takes everything. | | `multiple` | `True` | `False` keeps only the last file. | | `browse` | `True` | A click opens the file dialog. | | `show_files` | `False` | Lists the files under the text (each with an x). | | `files` | `()` | The dropped paths. | | `disabled` | `False` | Takes nothing. | | `live` | `True` | `False` draws it without taking files (the designer's canvas). | Events: `on_drop`, `on_files`, `on_reject`, `on_enter`, `on_leave` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#dropzone) #### Related - [File picker](https://albakore.github.io/pyzed/library/file-input/): A path field with a button that opens the system's file or folder dialog. - [Card](https://albakore.github.io/pyzed/library/card/): A bordered surface with an optional title and actions. ### Editor > A full code editor: highlighting, folding, minimap, git markers. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/editor/ :::tip[In plain words] A box for writing code, with colors, line numbers and everything a programmer expects. ::: A code editor with syntax highlighting in the theme colors (100+ languages), line numbers, git markers, auto-closing pairs, folding, a minimap and font zoom. It is **uncontrolled**: the text, cursor and undo history live in Rust, tied to `id`, and `text` is only the initial value. `on_change` receives the full text and `on_cursor` the `(line, column)`. `pz.code_editor` is the base widget without the theme. `ui.editor` · Category: [Code and tools](https://albakore.github.io/pyzed/library/#code-and-tools) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#editor) **Code:** ```python code = '''import pyzed as pz from pyzed import ui class Counter(pz.App): def __init__(self): self.count = 0 def view(self): return ui.button(f"Clicks: {self.count}", self.increment) ''' pz.container(ui.editor("counter.py", code, path="counter.py", markers={7: "modified", 10: "created"}), width=620, height=290) ``` #### When to use - For code, configuration files, logs you can edit, or any long text. - Use the file path as `id`: each file keeps its cursor and history when you switch tabs. - To replace the text from code, return `pz.Command.set_editor_text(id, text)`. #### Usage ```python import pyzed as pz from pyzed import ui from pathlib import Path class Editor(pz.App): def __init__(self): self.path = "main.py" self.text = Path(self.path).read_text() def save(self): Path(self.path).write_text(self.text) def view(self): return ui.editor(self.path, self.text, path=self.path, on_change=lambda text: setattr(self, "text", text)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Language ```python pz.container(ui.editor("v-py", "class Counter(pz.App):\n count = 0\n\n def view(self):\n return ui.button('Add', self.add)", path="counter.py"), width=470, height=110) ``` ```python pz.container(ui.editor("v-rs", "fn main() {\n println!(\"hi\");\n}\n", language="rust"), width=420, height=90) ``` ```python pz.container(ui.editor("v-json", '{\n "name": "notes",\n "version": 2\n}\n', language="json"), width=420, height=110) ``` ##### Options ```python pz.container(ui.editor("v-g", "class Counter(pz.App):\n count = 0\n\n def view(self):\n return ui.button('Add', self.add)", path="a.py", gutter=False), width=470, height=110) ``` ```python pz.container(ui.editor("v-m", "class Counter(pz.App):\n count = 0\n\n def view(self):\n return ui.button('Add', self.add)", path="a.py", markers={2: "created", 5: "modified"}), width=470, height=110) ``` ```python pz.container(ui.editor("v-mm", "class Counter(pz.App):\n count = 0\n\n def view(self):\n return ui.button('Add', self.add)", path="a.py", minimap=True), width=470, height=124) ``` ```python pz.container(ui.editor("v-ws", "class Counter(pz.App):\n count = 0\n\n def view(self):\n return ui.button('Add', self.add)", path="a.py", show_whitespace=True), width=470, height=110) ``` ```python pz.container(ui.editor("v-ph", "", placeholder="Write something…"), width=420, height=60) ``` ```python pz.container(ui.editor("v-fs", "print(\"big\")\n", path="a.py", font_size=16), width=420, height=60) ``` #### Examples ##### Folding, code lens and minimap Blocks fold by indentation (Ctrl+Shift+[ and ]), `annotations` adds a code lens above a line and `minimap=True` draws the overview on the right. **Code:** ```python code = '''import pyzed as pz from pyzed import ui class Counter(pz.App): def __init__(self): self.count = 0 def increment(self): self.count += 1 def view(self): return ui.button(f"Clicks: {self.count}", self.increment) ''' pz.container(ui.editor("lens.py", code, path="counter.py", minimap=True, annotations={5: "1 reference"}), width=680, height=290) ``` ##### Cursor and whitespace `cursor_shape` is `"bar"`, `"block"`, `"underline"` or `"hollow"`; `show_whitespace=True` draws spaces and tabs; `wrap=True` wraps long lines. **Code:** ```python pz.container(ui.editor("ws.py", "def greet(name):\n return f'Hello, {name}'\n", path="ws.py", cursor_shape="block", show_whitespace=True, font_size=15), width=620, height=120) ``` #### Events Editor has **6 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_change` | `ui.editor`, `pz.code_editor` | `(text)` | Callable that receives the new value. | | `on_cursor` | `ui.editor`, `pz.code_editor` | `(line, column)` | Callable that receives `(line, column)`. | | `on_scroll` | `ui.editor`, `pz.code_editor` | `(info)` | Called on scroll. | | `on_zoom` | `ui.editor`, `pz.code_editor` | `(step)` | Callable that receives `1`, `-1` or `0` for Ctrl+= / Ctrl+- / Ctrl+0 and Ctrl+wheel. | | `on_action` | `ui.editor`, `pz.code_editor` | `(name)` | Callable that receives the name of each editor action that runs (`"undo"`, `"select_next"`…), e.g. to count them. | | `on_hover` | `ui.editor`, `pz.code_editor` | `()` | Callable that receives `{line, column, start, end, x, y, height}` (the word under the mouse, from 1, and its place in the editor) after the mouse rests on it, and `None` when it leaves (hover cards). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Editor(pz.App): def __init__(self): self.text = "print('hello')\n" self.cursor = (1, 1) self.font_size = 14 def zoom(self, step): # on_zoom: 1, -1 or 0 (Ctrl+=, Ctrl+-, Ctrl+0) self.font_size = 14 if step == 0 else self.font_size + step def view(self): line, column = self.cursor return pz.column([ ui.editor("main.py", self.text, path="main.py", font_size=self.font_size, height=200, on_change=lambda text: setattr(self, "text", text), # every edit on_cursor=lambda ln, col: setattr(self, "cursor", (ln, col)), # from 1 on_zoom=self.zoom, on_action=lambda name: print("ran", name)), # "undo"... ui.status_bar([], [ui.status_item(f"Ln {line}, Col {column}")]), ]) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Edited: text: str @dataclass class Moved: line: int column: int class Editor(pz.App): text, cursor = "print('hello')\n", (1, 1) def update(self, message): match message: case Edited(text): self.text = text case Moved(line, column): self.cursor = (line, column) def view(self): return ui.editor("main.py", self.text, path="main.py", height=200, on_change=Edited, on_cursor=Moved) # the classes build the messages ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: text: str = "print('hello')\n" line: int = 1 column: int = 1 def view(state, set_state): return pz.column([ ui.editor("main.py", state.text, path="main.py", height=200, on_change=lambda text: set_state(text=text), on_cursor=lambda line, column: set_state(line=line, column=column)), ui.label(f"Ln {state.line}, Col {state.column}"), ]) ``` #### Properties and API ##### `ui.editor` ```python editor( id, text='', *, language=None, path=None, on_change=None, on_cursor=None, markers=None, font_size=None, line_height=None, gutter=True, wrap=False, active_line=True, height='fill', placeholder=None, annotations=None, show_whitespace=False, tab_size=None, hard_tabs=False, backspace_unindent=True, repeat_delay=None, repeat_rate=None, capture_keys=(), on_scroll=None, auto_close=True, folding=True, minimap=False, cursor_shape='bar', cursor_blink=True, cursor_width=2.0, cursor_color=None, on_zoom=None, on_action=None, highlights=None, match_brackets=True, selection_highlight=True, font=None, keymap=None, scrollbar=True, readonly=False, on_hover=None, hover_delay=500, sticky_scroll=0, theme=None, ) ``` A code editor: highlighting with the theme colors, line numbers and git markers. | Property | Default | Description | | --- | --- | --- | | `id` | *required* | Identifies the buffer (use the file path). | | `text` | `""` | Initial text. | | `language` | `None` | Language. If missing, it is inferred from `path`. | | `path` | `None` | File path. | | `markers` | `None` | `{line: "created" \| "modified" \| "deleted"}`. | | `font_size` | `None` | Font size (defaults to the theme's). | | `line_height` | `None` | Line height. | | `gutter` | `True` | Shows line numbers. | | `wrap` | `False` | Line wrapping. | | `active_line` | `True` | Background color of the cursor line. | | `height` | `"fill"` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `placeholder` | `None` | Hint text shown when empty. | | `annotations` | `None` | `{line: "text"}` or `{line: ("text", color)}`: virtual text at the end of the line (code lens, diagnostics). | | `show_whitespace` | `False` | Draws spaces as `·` and tabs as `→`. | | `tab_size` | `None` | Tab inserts spaces up to the next multiple; Enter keeps the indentation (one more level after `:`); Backspace removes a level. | | `hard_tabs` | `False` | With `tab_size`: Tab, Enter and indent (Ctrl+]) use tab characters instead of spaces. | | `backspace_unindent` | `True` | With `tab_size`: Backspace in leading spaces removes a whole level (`False`: one space). | | `repeat_delay` | `None` | Milliseconds Backspace and Delete wait, held down, before repeating (`None`: the system's). | | `repeat_rate` | `None` | Deletions per second at most while Backspace or Delete is held down (`None`: the system's pace). | | `capture_keys` | `()` | Keys the editor leaves to the app's `on_key` (`"up"`, `"enter"`…), e.g. while a completion list is open. | | `auto_close` | `True` | Closes brackets and quotes as you type (and wraps the selection). | | `folding` | `True` | Fold chevrons in the gutter; Ctrl+Shift+[ folds and Ctrl+Shift+] unfolds. | | `minimap` | `False` | `True` (or a width in pixels) shows a minimap on the right. | | `cursor_shape` | `"bar"` | `"bar"`, `"block"`, `"underline"` or `"hollow"`. | | `cursor_blink` | `True` | Whether the cursor blinks. | | `cursor_width` | `2.0` | Width of the bar cursor. | | `cursor_color` | `None` | Cursor color (the theme's player color by default). | | `highlights` | `None` | Ranges painted behind the text in the theme's search color: `[(line, column, end_line, end_column)]`, from 1, with exclusive ends. | | `match_brackets` | `True` | Outlines the bracket that matches the one next to the cursor (Ctrl+M jumps to it). | | `selection_highlight` | `True` | Highlights the other occurrences of the selected text (Ctrl+D adds the next one as a cursor). | | `font` | `None` | Typeface: `"mono"` by default; `"sans"` makes a multi-line text box, like a chat's message box. | | `keymap` | `None` | Zed-style `{binding: action}` dict (`{"ctrl-shift-d": "duplicate_line_down"}`); `None` as the action removes a default key. Build it from per-action overrides with `pyzed.ui.editor.keymap_for`. | | `scrollbar` | `True` | `False` hides the scrollbars. | | `readonly` | `False` | `True` lets the text be selected and copied but not changed (a log, a traceback). | | `hover_delay` | `500` | Milliseconds the mouse rests on a word before `on_hover` is called. | | `sticky_scroll` | `0` | How many lines of the enclosing blocks (`class`, `def`, `if`…) stay pinned at the top while scrolling (`0`: none). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_change`, `on_cursor`, `on_scroll`, `on_zoom`, `on_action`, `on_hover` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#editor) ##### `ui.language_token` ```python language_token(path) ``` Returns the highlighter language token for a path (`"main.rs"` → `"rs"`). | Property | Default | Description | | --- | --- | --- | | `path` | *required* | File path. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#language_token) ##### `pz.code_editor` ```python code_editor( id, text='', *, language='txt', size=14.0, line_height=None, font=None, width=None, height=None, padding=None, syntax=None, bg=None, color=None, selection_color=None, placeholder=None, placeholder_color=None, gutter=True, gutter_color=None, gutter_active_color=None, gutter_width=None, markers=None, wrap=False, on_change=None, on_cursor=None, active_line=None, scrollbar_color=None, annotations=None, whitespace=None, tab_size=None, capture_keys=None, on_scroll=None, auto_close=False, folding=False, minimap=None, minimap_thumb=None, cursor_shape='bar', cursor_width=2.0, cursor_blink=True, cursor_color=None, on_zoom=None, on_action=None, highlights=None, highlight_color=None, match_brackets=True, selection_highlight=True, keymap=None, scrollbar=True, readonly=False, hard_tabs=False, backspace_unindent=True, repeat_delay=None, repeat_rate=None, on_hover=None, hover_delay=500.0, sticky_scroll=0, ) ``` A code editor with syntax highlighting, line numbers and git markers, based on Iced's `text_editor`. It is **uncontrolled**: `text` is only the initial value for that `id`; the text, cursor and history live in Rust. Use `Command.set_editor_text` to replace it. For the themed editor use [`ui.editor`](https://albakore.github.io/pyzed/components/code/). | Property | Default | Description | | --- | --- | --- | | `id` | *required* | Identifies the buffer. Reuse it to keep state across renders. | | `text` | `""` | Initial text. | | `language` | `"txt"` | Language extension or name (`"py"`, `"rs"`, `"json"`…). | | `size` | `14.0` | Font size. | | `line_height` | `None` | Line height in pixels. | | `font` | `None` | Family (monospace by default). | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `padding` | `None` | Inner padding: `8`, `(vertical, horizontal)` or `(top, right, bottom, left)`. | | `syntax` | `None` | Map of TextMate scopes to colors (provided by `Theme.syntax_scopes()`). | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `color` | `None` | Text or icon color. | | `selection_color` | `None` | Selection color. | | `placeholder` | `None` | Hint text shown when empty. | | `placeholder_color` | `None` | Placeholder color. | | `gutter` | `True` | Shows line numbers. | | `gutter_color` | `None` | Line number color. | | `gutter_active_color` | `None` | Color of the cursor line's number. | | `gutter_width` | `None` | Gutter width (automatic by default). | | `markers` | `None` | `{line: color}` for git markers in the gutter (lines from 1). | | `wrap` | `False` | Line wrapping. | | `active_line` | `None` | Background color of the cursor line. | | `scrollbar_color` | `None` | Scrollbar color. | | `annotations` | `None` | `{line: "text"}` or `{line: ("text", color)}`: virtual text at the end of the line (code lens, diagnostics). | | `whitespace` | `None` | Draws spaces as `·` and tabs as `→` in this color. | | `tab_size` | `None` | Tab inserts spaces up to the next multiple; Enter keeps the indentation; Backspace removes a level. | | `capture_keys` | `None` | Keys the editor leaves to the app's `on_key` (`"up"`, `"enter"`…), e.g. while a completion list is open. | | `auto_close` | `False` | Typing a bracket or quote also inserts its closing pair. | | `folding` | `False` | Fold chevrons in the gutter and Ctrl+Shift+[ / ]. | | `minimap` | `None` | Width of the minimap in pixels (`None`: no minimap). | | `minimap_thumb` | `None` | Color of the minimap's visible-area highlight. | | `cursor_shape` | `"bar"` | `"bar"`, `"block"`, `"underline"` or `"hollow"`. | | `cursor_width` | `2.0` | Width of the bar cursor. | | `cursor_blink` | `True` | Whether the cursor blinks. | | `cursor_color` | `None` | Cursor color. | | `highlights` | `None` | Ranges painted behind the text (search results): `[(line, column, end_line, end_column)]`, from 1, with exclusive ends. | | `highlight_color` | `None` | Color of `highlights`. | | `match_brackets` | `True` | Outlines the bracket that matches the one next to the cursor. | | `selection_highlight` | `True` | Highlights the other occurrences of the selected text. | | `keymap` | `None` | Zed-style `{binding: action}` dict; `None` as the action removes a default key (`pyzed.ui.editor.keymap_for` builds one from per-action overrides). | | `scrollbar` | `True` | `False` hides the scrollbars. | | `readonly` | `False` | `True` lets the text be selected and copied but not changed (a log, a traceback). | | `hard_tabs` | `False` | With `tab_size`: Tab, Enter and indent (Ctrl+]) use tab characters instead of spaces. | | `backspace_unindent` | `True` | With `tab_size`: Backspace in leading spaces removes a whole level (`False`: one space). | | `repeat_delay` | `None` | Milliseconds Backspace and Delete wait, held down, before repeating (`None`: the system's). | | `repeat_rate` | `None` | Deletions per second at most while Backspace or Delete is held down (`None`: the system's pace). | | `hover_delay` | `500.0` | Milliseconds the mouse rests on a word before `on_hover` is called. | | `sticky_scroll` | `0` | How many lines of the enclosing blocks (`class`, `def`, `if`…) stay pinned at the top while scrolling (`0`: none). | Events: `on_change`, `on_cursor`, `on_scroll`, `on_zoom`, `on_action`, `on_hover` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#code_editor) #### Related - [Terminal](https://albakore.github.io/pyzed/library/terminal/): A read-only terminal view with ANSI colors. - [Console](https://albakore.github.io/pyzed/library/console/): A dev-tools style log with levels, filter, copy and clear. - [Workspace](https://albakore.github.io/pyzed/library/workspace/): The layout of an editor-style window: title bar, docks, center, status bar. ### Edits bar > The files an agent changed, with Keep all and Reject all. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/edits-bar/ :::tip[In plain words] A bar that lists the files an AI assistant changed, so you can keep or undo the changes. ::: `ui.EditsBar` is a component that lists the files an agent changed: `3 files changed` with the lines added and removed, Reject all and Keep all. Clicking the title unfolds one row per file with its diff stat and buttons to reject or keep that file alone; clicking a file's name reports `on_open`. `files` are dicts or objects with `path` and optional `added` and `removed` line counts. The file events (`on_keep_file`, `on_reject_file`, `on_open`) carry the path in `event.value`. `ui.EditsBar` · Category: [AI agents](https://albakore.github.io/pyzed/library/#ai-agents) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#editsbar) **Code:** ```python pz.container(ui.EditsBar(files=[ {"path": "app/storage.py", "added": 12, "removed": 3}, {"path": "app/forms/login.py", "added": 40, "removed": 0}, {"path": "tests/test_login.py", "added": 18, "removed": 2}, ], on_keep=on_keep, on_reject=on_reject), width=520) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - Under an agent's chat, once it has edited files, so the user reviews them before keeping them. #### Usage ```python import pyzed as pz from pyzed import ui class Review(pz.App): def __init__(self): self.files = [{"path": "app/storage.py", "added": 12, "removed": 3}] def keep(self, path=None): # None: every file self.files = [f for f in self.files if path is not None and f["path"] != path] def view(self): return ui.EditsBar(files=self.files, on_keep=lambda e: self.keep(), on_keep_file=lambda e: self.keep(e.value), on_open=lambda e: self.open(e.value)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### State Unfolded ones are drawn as they look after a click on the header. ```python pz.container(ui.EditsBar(files=[{"path": "app.py", "added": 12, "removed": 3}, {"path": "ui/form.py", "added": 40, "removed": 0}]), width=440) ``` ```python pz.container(ui.EditsBar(files=[{"path": "app.py", "added": 12, "removed": 3}, {"path": "ui/form.py", "added": 40, "removed": 0}]), width=440) ``` ```python pz.container(ui.EditsBar(files=[{"path": "app.py", "added": 2, "removed": 2}]), width=440) ``` ```python pz.container(ui.EditsBar(files=[{"path": "app.py"}, {"path": "README.md"}]), width=440) ``` #### Events Edits bar has **5 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Handler gets | When | | --- | --- | --- | | `on_keep` | `(event)` | Keep all. | | `on_reject` | `(event)` | Reject all. | | `on_keep_file` | `(event)` | Keep on a file (`event.value` is its path). | | `on_reject_file` | `(event)` | Reject on a file. | | `on_open` | `(event)` | A file was clicked. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Review(pz.App): def __init__(self): self.files = [{"path": "app/storage.py", "added": 12, "removed": 3}, {"path": "tests/test_storage.py", "added": 8, "removed": 0}] def drop(self, path=None): # None: every file self.files = [f for f in self.files if path is not None and f["path"] != path] def view(self): # event.value is the file's path return ui.EditsBar(files=self.files, on_keep=lambda e: self.drop(), on_reject=lambda e: self.drop(), on_keep_file=lambda e: self.drop(e.value), on_reject_file=lambda e: self.drop(e.value), on_open=lambda e: print("open", e.value)) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Done: path: str = "" class Review(pz.App): files = [{"path": "app/storage.py", "added": 12, "removed": 3}] def update(self, message): match message: case Done(""): self.files = [] case Done(path): self.files = [f for f in self.files if f["path"] != path] def view(self): return ui.EditsBar(files=self.files, on_keep=Done(), on_keep_file=lambda e: Done(e.value)) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: files: tuple = ({"path": "app/storage.py", "added": 12, "removed": 3},) def view(state, set_state): without = lambda path: tuple(f for f in state.files if f["path"] != path) return ui.EditsBar(files=list(state.files), on_keep=lambda e: set_state(files=()), on_keep_file=lambda e: set_state(files=without(e.value))) ``` #### Properties and API ##### `ui.EditsBar` ```python class EditsBar ``` A component listing the files an agent changed, like Zed's edits bar: `3 files changed` with Reject all and Keep all, unfolding to one row per file with its diff stat, Reject and Keep. | Property | Default | Description | | --- | --- | --- | | `files` | `None` | Dicts or objects with `path` and optional `added` and `removed` line counts. | | `theme` | `None` | Theme. | Events: `on_keep`, `on_reject`, `on_keep_file`, `on_reject_file`, `on_open` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#editsbar) #### Related - [Diff view](https://albakore.github.io/pyzed/library/diff-view/): An edit as colored lines: added in green, removed in red. - [Diff stat](https://albakore.github.io/pyzed/library/diff-stat/): `+12 −3` with GitHub-style blocks. - [Tool call](https://albakore.github.io/pyzed/library/tool-call/): One step of an AI agent: what it did, its result, and Allow or Reject. ### Effects > Glow, bloom, glass and opacity as style properties. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/effects/ :::tip[In plain words] Glows, frosted glass and transparency you can add to any box. ::: Visual effects are [style](https://albakore.github.io/pyzed/theming/styles/) properties: `glow` (a soft halo), `bloom` (a wide, bright spill of light), `glass` (a translucent, frosted panel), `opacity`, and `translate` and `scale`, which move or scale the drawing without changing the layout. Animations can change `glow` too. `pz.Style` · Category: [Content](https://albakore.github.io/pyzed/library/#content) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#style) **Code:** ```python pz.container(pz.row([ pz.container(ui.label("Glass"), width=150, height=70, padding=14).style(glass=True, radius=12), pz.container(ui.label("Glow"), width=150, height=70, padding=14).style( background="#0b1220", radius=12, glow=("#22d3ee", 18)), pz.container(ui.label("Bloom"), width=150, height=70, padding=14).style( background="#1a0b16", radius=12, bloom=("#f472b6", 0.8)), pz.container(ui.label("Opacity"), width=150, height=70, padding=14).style( background="#0b1220", radius=12, opacity=0.5), ], spacing=24), padding=32).style( background=pz.Gradient(["#0f172a", "#312e81", "#0e7490"], angle=90), radius=14) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - To highlight the primary action or a live state (recording, connected). - For floating panels over colorful backgrounds (glass). #### Usage ```python import pyzed as pz from pyzed import ui pz.container(pz.row([ pz.container(ui.label("Glass"), width=150, height=70, padding=14).style(glass=True, radius=12), pz.container(ui.label("Glow"), width=150, height=70, padding=14).style( background="#0b1220", radius=12, glow=("#22d3ee", 18)), pz.container(ui.label("Bloom"), width=150, height=70, padding=14).style( background="#1a0b16", radius=12, bloom=("#f472b6", 0.8)), pz.container(ui.label("Opacity"), width=150, height=70, padding=14).style( background="#0b1220", radius=12, opacity=0.5), ], spacing=24), padding=32).style( background=pz.Gradient(["#0f172a", "#312e81", "#0e7490"], angle=90), radius=14) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Effects ```python pz.container(pz.container(ui.label("Glass"), width=130, height=60, padding=12).style(glass=True, radius=12), padding=24).style(background=pz.Gradient(["#0f172a", "#312e81", "#0e7490"], angle=90), radius=12) ``` ```python pz.container(pz.container(ui.label("Glow"), width=130, height=60, padding=12).style(background="#0b1220", radius=12, glow=("#22d3ee", 18)), padding=24).style(background=pz.Gradient(["#0f172a", "#312e81", "#0e7490"], angle=90), radius=12) ``` ```python pz.container(pz.container(ui.label("Bloom"), width=130, height=60, padding=12).style(background="#1a0b16", radius=12, bloom=("#f472b6", 0.8)), padding=24).style(background=pz.Gradient(["#0f172a", "#312e81", "#0e7490"], angle=90), radius=12) ``` ```python pz.container(pz.container(ui.label("Opacity"), width=130, height=60, padding=12).style(background="#0b1220", radius=12, opacity=0.5), padding=24).style(background=pz.Gradient(["#0f172a", "#312e81", "#0e7490"], angle=90), radius=12) ``` ```python pz.container(pz.container(ui.label("Scale"), width=130, height=60, padding=12).style(background="#0b1220", radius=12, scale=1.15), padding=24).style(background=pz.Gradient(["#0f172a", "#312e81", "#0e7490"], angle=90), radius=12) ``` ```python pz.container(pz.container(ui.label("Translate"), width=130, height=60, padding=12).style(background="#0b1220", radius=12, translate=(16, 8)), padding=24).style(background=pz.Gradient(["#0f172a", "#312e81", "#0e7490"], angle=90), radius=12) ``` #### Events Effects has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.Style` ```python class Style ``` A reusable set of style properties for `widget.style(...)`, a component's `style=` or `App.style`. Combine styles with `|` (the right one wins). See [Styles](https://albakore.github.io/pyzed/theming/styles/). | Property | Default | Description | | --- | --- | --- | | `*styles` | — | Styles, dicts or style names to start from. | | `**props` | — | Properties: `background`, `color`, `font`, `weight`, `italic`, `size`, `line_height`, `border_color`, `border_width`, `border` (`(width, color)`), `radius`, `shadow`, `padding`, `margin`, `width`, `height`, `max_width`, `max_height`, `min_width`, `min_height`, `align_x`, `align_y`, `clip`. Effects: `opacity`, `translate` (`(x, y)`, pixels or `"50%"`), `scale`, `glow` (a color, a size or `(color, size)`), `bloom` (a color or `(color, intensity)`) and `glass` (`True`, a tint or `{"tint", "strength"}`). States: `hover`, `pressed` (or `active`) and `focus`, each with the properties to show then. `transition`: milliseconds, `True` or `{"duration", "easing", "delay"}`. `media`: `{query: style}` applied when the window matches. Colors may be theme tokens. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#style) #### Related - [Animation](https://albakore.github.io/pyzed/library/animation/): Presets, keyframes and transitions for any widget. - [Card](https://albakore.github.io/pyzed/library/card/): A bordered surface with an optional title and actions. ### Empty state > A centered placeholder for empty lists and searches. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/empty-state/ :::tip[In plain words] What a screen shows when there is nothing in it yet, with a hint of what to do next. ::: A centered icon, title, description and actions for a place that has nothing to show yet. `ui.empty_state` · Category: [Feedback](https://albakore.github.io/pyzed/library/#feedback) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#empty_state) **Code:** ```python ui.empty_state("No results", "Try a different search.", icon="search", actions=[ui.button("Clear filters", on_clear, size="sm")]) ``` #### When to use - For an empty list, a search with no results, or a panel before the first file is opened. - Offer the next step as an action (Create, Clear filters, Open folder). #### Usage ```python from pyzed import ui ui.empty_state("No results", "Try a different search.", icon="search", actions=[ui.button("Clear filters", on_clear, size="sm")]) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python ui.empty_state("No notifications") ``` ```python ui.empty_state("No results", "Try a different search.", icon="search") ``` ```python ui.empty_state("No projects yet", "Create one to get started.", icon="folder-plus", actions=[ui.button("New project", on_new, variant="solid", size="sm")]) ``` ##### States and events ```python ui.empty_state("No results", "Try another search", icon="search", size="sm", height="shrink") ``` ```python ui.empty_state("No projects", "Create one to start", icon="folder", size="lg", height=220) ``` #### Events Empty state has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.empty_state` ```python empty_state( title, description=None, *, icon='inbox', actions=(), size='md', height='fill', theme=None, ) ``` A centered placeholder for empty lists, searches with no results, etc. | Property | Default | Description | | --- | --- | --- | | `title` | *required* | Title. | | `description` | `None` | Secondary text. | | `icon` | `"inbox"` | Name of a Lucide icon (`pyzed icons` lists them). | | `actions` | `()` | Extra widgets (usually buttons) shown as actions. | | `size` | `"md"` | `"sm"`, `"md"` or `"lg"`. | | `height` | `"fill"` | `"fill"` (default), pixels or `"shrink"`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#empty_state) #### Related - [Callout](https://albakore.github.io/pyzed/library/callout/): An inline notice with a title, text and actions. - [Keybinding hint](https://albakore.github.io/pyzed/library/keybinding-hint/): A muted “Open file Ctrl P” hint. - [Card](https://albakore.github.io/pyzed/library/card/): A bordered surface with an optional title and actions. ### Error boundary > Draws a part of the view, or an error card in its place when it fails. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/error-boundary/ :::tip[In plain words] A safety net for one part of a window: if that part breaks, a small error box shows there and the rest of the app keeps working. ::: `ui.error_boundary(build)` returns `build()` or, when it raises, an error card in its place, so one broken part of the view (a sidebar, a panel) never takes the whole window down. The card shows the error, the file and line it comes from and a Copy error button; `on_details` adds a Details button and `fallback` replaces the card with your own widget. `on_error(info)` is told about the error each time the part fails to draw. `ui.ErrorInfo` describes an error (its type, message, traceback and origin) and `ui.error_card` is the card on its own. `ui.error_boundary` · Category: [Feedback](https://albakore.github.io/pyzed/library/#feedback) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#error_boundary) **Code:** ```python def totals(): values = [] return ui.label(f"Average: {sum(values) / len(values)}") pz.row([ ui.card(ui.muted("This panel keeps working."), title="Files", width=200), pz.container(ui.error_boundary(totals, title="Totals", on_details=on_details), width=380), ], spacing=12, align="center") ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - Around each panel of a big window, so a bug in one leaves the others working. - Around parts that draw data you don't control: a plugin, a file the user opened, a reply from a server. - Open an [Error dialog](https://albakore.github.io/pyzed/library/error-dialog/) from `on_details` to show the whole traceback. #### Usage ```python import pyzed as pz from pyzed import ui class Report(pz.App): def __init__(self): self.error = None # the ui.ErrorInfo shown in the dialog def totals(self): ... # may raise def show(self, info): self.error = info def close(self): self.error = None def view(self): page = pz.row([ self.files(), ui.error_boundary(self.totals, title="Totals", on_details=self.show), ]) dialog = ui.error_dialog(self.error, self.close) if self.error else None return ui.dialog_layer(page, dialog, on_dismiss=self.close) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Boundary While `build()` works the boundary returns its widget untouched; only a part that raises is replaced. ```python ui.error_boundary(lambda: ui.label("Average: 4.2")) ``` ```python def totals(): values = [] return ui.label(f"Average: {sum(values) / len(values)}") pz.container(ui.error_boundary(totals), width=360) ``` ```python def totals(): values = [] return ui.label(f"Average: {sum(values) / len(values)}") pz.container(ui.error_boundary(totals, title="Totals"), width=360) ``` ```python def totals(): values = [] return ui.label(f"Average: {sum(values) / len(values)}") pz.container(ui.error_boundary(totals, title="Totals", on_details=on_details), width=360) ``` ```python def totals(): values = [] return ui.label(f"Average: {sum(values) / len(values)}") ui.error_boundary(totals, fallback=lambda info: ui.callout( "Totals are not available", info.summary, tint="warning")) ``` ##### Error card `ui.error_card` is the card on its own, for errors you catch yourself. ```python info = ui.ErrorInfo("KeyError", "'email'", origin=("app/forms.py", 42), where="Sign-up form") pz.container(ui.error_card(info), width=360) ``` ```python info = ui.ErrorInfo("KeyError", "'email'", origin=("app/forms.py", 42), where="Sign-up form") pz.container(ui.error_card(info, title="The form could not be loaded", actions=[ui.button("Retry", on_retry, icon="rotate-ccw", size="sm", variant="ghost")]), width=360) ``` ```python pz.container(ui.error_card(ui.ErrorInfo("TimeoutError", "the server took too long")), width=360) ``` #### Events Error boundary has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_error` | `ui.error_boundary` | `(info)` | Receives the `ui.ErrorInfo`. | | `on_details` | `ui.error_boundary`, `ui.error_card` | `(info)` | Adds a Details button; receives the `ui.ErrorInfo` (open a `ui.error_dialog`). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Report(pz.App): def __init__(self): self.values = [] self.error = None # the ui.ErrorInfo shown in the dialog def totals(self): return ui.label(f"Average: {sum(self.values) / len(self.values)}") # raises on [] def view(self): page = ui.error_boundary(self.totals, title="Totals", on_error=lambda info: print(info.message), # every failure on_details=lambda info: setattr(self, "error", info)) # Details dialog = ui.error_dialog(self.error, lambda: setattr(self, "error", None)) if self.error else None return ui.dialog_layer(page, dialog) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class ShowError: info: object class Report(pz.App): error = None def totals(self): return ui.label(f"Average: {sum([]) / len([])}") def update(self, message): match message: case ShowError(info): self.error = info case "close": self.error = None def view(self): page = ui.error_boundary(self.totals, title="Totals", on_details=ShowError) return ui.dialog_layer(page, ui.error_dialog(self.error, "close") if self.error else None) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: values: tuple = () failures: int = 0 def totals(values): return ui.label(f"Average: {sum(values) / len(values)}") def view(state, set_state): return pz.column([ ui.error_boundary(lambda: totals(state.values), title="Totals", on_error=lambda info: set_state(failures=state.failures + 1)), ui.button("Add 10", lambda: set_state(values=state.values + (10,))), ], spacing=8, width=380) ``` #### Tips :::tip The boundary runs `build()` on every redraw, so `on_error` is called again each time the part fails. To report an error once, compare it with the last one: two `ErrorInfo` with the same type, message, traceback and origin are equal (`time` is left out). `ErrorInfo.from_exception(err)` describes any exception you catch yourself, and `info.report()` gives the text to paste in a bug report. ::: #### Properties and API ##### `ui.error_boundary` ```python error_boundary( build, *, on_error=None, title=None, where='', on_details=None, fallback=None, theme=None, ) ``` Draws `build()`, or an error card when it raises, so one part of the view that fails never takes the whole window down (like React's error boundaries). `on_error(info)` is told about the error each time the part is drawn and fails, so report it once (compare `info.traceback`). | Property | Default | Description | | --- | --- | --- | | `build` | *required* | A function that returns the part's widget. | | `title` | `None` | Heading of the card (and the error's `where`). | | `where` | `""` | What the part is, for the report. | | `fallback` | `None` | Your own widget for the error: `fallback(info)`. | | `theme` | `None` | Theme override. | Events: `on_error`, `on_details` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#error_boundary) ##### `ui.error_card` ```python error_card(info, *, title=None, on_details=None, actions=(), theme=None) ``` The card `ui.error_boundary` draws in place of what failed: the error, where it comes from and a Copy error button (and Details with `on_details`). | Property | Default | Description | | --- | --- | --- | | `info` | *required* | A `ui.ErrorInfo`. | | `title` | `None` | Heading. | | `actions` | `()` | More buttons after them. | | `theme` | `None` | Theme override. | Events: `on_details` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#error_card) ##### `ui.ErrorInfo` ```python @dataclass class ErrorInfo(kind, message, traceback='', origin=None, where='', time=0.0) ``` An error as `ui.error_card` and `ui.error_dialog` show it: `kind` (the exception's type), `message`, the whole `traceback`, the `origin` `(path, line)` it comes from (the last frame outside the standard library, installed packages and Pyzed), `where` it happened and `time`. `ErrorInfo.from_exception(err, where=...)` makes one (`prefer=` picks which frames may be the origin); `ErrorInfo.current()` describes the exception being handled. `summary` is `Type: message`, `location` is `file.py:12` and `report()` is everything as text for a bug report. | Property | Default | Description | | --- | --- | --- | | `kind` | *required* | The exception's type name. | | `message` | *required* | Its message. | | `traceback` | `""` | The whole traceback, as Python prints it. | | `origin` | `None` | `(path, line)` of the code it comes from, or `None`. | | `where` | `""` | What was running. | | `time` | `0.0` | When it happened (`time.time()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#errorinfo) #### Related - [Error dialog](https://albakore.github.io/pyzed/library/error-dialog/): What went wrong, where, and the traceback, with Copy and Go to source. - [Callout](https://albakore.github.io/pyzed/library/callout/): An inline notice with a title, text and actions. - [Console](https://albakore.github.io/pyzed/library/console/): A dev-tools style log with levels, filter, copy and clear. ### Error dialog > What went wrong, where, and the traceback, with Copy and Go to source. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/error-dialog/ :::tip[In plain words] A window that pops up when something fails, saying what went wrong and where, with a button to copy it for a bug report. ::: `ui.error_dialog(info, on_close)` shows an error in a dialog: its message, where it happened, the file and line it comes from and the traceback in a read-only editor, where any part can be selected and copied. Its buttons copy the whole report, go to the origin (`on_go_to`, labeled `go_to_label`), show it among the logs (`on_logs`) and close. `more` adds a line saying how many other errors came after it. `info` is a `ui.ErrorInfo`; show the dialog with a [Dialog layer](https://albakore.github.io/pyzed/library/dialog-layer/). `ui.error_dialog` · Category: [Dialogs](https://albakore.github.io/pyzed/library/#dialogs) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#error_dialog) **Code:** ```python def average(values): return sum(values) / len(values) try: average([]) except ZeroDivisionError as err: info = ui.ErrorInfo.from_exception(err, where="Totals") ui.dialog_layer(main_view(), ui.error_dialog(info, on_close, on_go_to=on_go_to, on_logs=on_logs, width=620)) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - When something the user asked for fails (saving, exporting, running a script) and the details matter. - From the Details button of an [Error boundary](https://albakore.github.io/pyzed/library/error-boundary/). - For a short message without a traceback, use an [Alert](https://albakore.github.io/pyzed/library/alert/) with `kind="error"`. #### Usage ```python import pyzed as pz from pyzed import ui class Notes(pz.App): def __init__(self): self.error = None def save(self): try: write_notes(self.notes) except OSError as err: self.error = ui.ErrorInfo.from_exception(err, where="Save") def close_error(self): self.error = None def view(self): dialog = ui.error_dialog(self.error, self.close_error) if self.error else None return ui.dialog_layer(self.page(), dialog, on_dismiss=self.close_error) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options Without a traceback the dialog leaves out the code box, as with an `ErrorInfo` you build yourself. ```python def average(values): return sum(values) / len(values) try: average([]) except ZeroDivisionError as err: info = ui.ErrorInfo.from_exception(err, where="Totals") ui.error_dialog(info, on_close, width=480) ``` ```python def average(values): return sum(values) / len(values) try: average([]) except ZeroDivisionError as err: info = ui.ErrorInfo.from_exception(err, where="Totals") ui.error_dialog(info, on_close, on_go_to=on_go_to, go_to_label="Open app.py", width=480) ``` ```python def average(values): return sum(values) / len(values) try: average([]) except ZeroDivisionError as err: info = ui.ErrorInfo.from_exception(err, where="Totals") ui.error_dialog(info, on_close, on_logs=on_logs, width=480) ``` ```python def average(values): return sum(values) / len(values) try: average([]) except ZeroDivisionError as err: info = ui.ErrorInfo.from_exception(err, where="Totals") ui.error_dialog(info, on_close, more=2, width=480) ``` **} alt={** ```python def average(values): return sum(values) / len(values) try: average([]) except ZeroDivisionError as err: info = ui.ErrorInfo.from_exception(err, where="Totals") ui.error_dialog(info, on_close, title="The totals could not be computed", width=480) ``` ```python info = ui.ErrorInfo("PermissionError", "[Errno 13] Permission denied: 'notes.md'", where="Save") ui.error_dialog(info, on_close, width=480) ``` #### Events Error dialog has **3 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_close` | `()` | Close button and Escape. | | `on_go_to` | `()` | Adds the go-to button (open the file at the line). | | `on_logs` | `()` | Adds a Show in Logs button. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Notes(pz.App): def __init__(self): try: open("/no/such/file") except OSError as err: self.error = ui.ErrorInfo.from_exception(err, where="Open") def close(self): # on_close: the button and Escape self.error = None def view(self): dialog = ui.error_dialog(self.error, self.close, on_go_to=lambda: print("go to", self.error.origin), # adds Go to on_logs=lambda: print("show logs")) if self.error else None return ui.dialog_layer(main_view(), dialog, on_dismiss=self.close) ``` **Declarative:** ```python class Notes(pz.App): error = ui.ErrorInfo("FileNotFoundError", "No such file: notes.txt") def update(self, message): match message: case "close": self.error = None case "logs": print("show logs") def view(self): dialog = ui.error_dialog(self.error, "close", on_logs="logs") if self.error else None return ui.dialog_layer(main_view(), dialog, on_dismiss="close") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: error: object = ui.ErrorInfo("FileNotFoundError", "No such file: notes.txt") def view(state, set_state): close = lambda: set_state(error=None) dialog = ui.error_dialog(state.error, close) if state.error else None return ui.dialog_layer(main_view(), dialog, on_dismiss=close) ``` #### Tips :::tip `on_go_to` receives no arguments: read the file and line from `info.origin` (a `(path, line)` pair, or `None`) and open it there. The traceback box is a read-only editor, so the user can select a single line and copy it, while Copy error copies `info.report()`. ::: #### Properties and API ##### `ui.error_dialog` ```python error_dialog( info, on_close, *, title=None, on_go_to=None, go_to_label=None, on_logs=None, more=0, width=680, theme=None, ) ``` A dialog with an error: its message, where it happened, the file and line it comes from and the traceback in a read-only editor (select and copy any part), with buttons to copy everything, go to the origin, see it among the logs and close. Show it with `ui.dialog_layer` or `ui.layer`. | Property | Default | Description | | --- | --- | --- | | `info` | *required* | A `ui.ErrorInfo`. | | `title` | `None` | Heading ("Something went wrong"). | | `go_to_label` | `None` | Its text ("Go to source"). | | `more` | `0` | How many other errors came after it (a line says so). | | `width` | `680` | Width in pixels or a modal size. | | `theme` | `None` | Theme override. | Events: `on_close`, `on_go_to`, `on_logs` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#error_dialog) #### Related - [Error boundary](https://albakore.github.io/pyzed/library/error-boundary/): Draws a part of the view, or an error card in its place when it fails. - [Alert](https://albakore.github.io/pyzed/library/alert/): A message with one button. - [Dialog layer](https://albakore.github.io/pyzed/library/dialog-layer/): Centers a dialog over your view with a dimmed backdrop. - [Modal](https://albakore.github.io/pyzed/library/modal/): A dialog surface with title, content and footer buttons. ### Facepile > Overlapping collaborator avatars with +N. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/facepile/ :::tip[In plain words] A row of overlapping avatars that shows who is here. ::: Overlapping avatars of collaborators, as in the title bar of a collaborative editor. People beyond `max_shown` are grouped into `+N`. `ui.facepile` · Category: [Data](https://albakore.github.io/pyzed/library/#data) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#facepile) **Code:** ```python pz.column([ ui.facepile(["Ana", "Luis", "Kev", "Marta"]), ui.facepile(["Ana", "Luis", "Kev", "Marta", "Sam", "Jo", "Lee", "Max"], size=28, max_shown=4), ], spacing=16, align="center") ``` #### When to use - To show who is in a project, a call or a document without listing names. #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ ui.facepile(["Ana", "Luis", "Kev", "Marta"]), ui.facepile(["Ana", "Luis", "Kev", "Marta", "Sam", "Jo", "Lee", "Max"], size=28, max_shown=4), ], spacing=16, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python ui.facepile(["Ana", "Luis"]) ``` ```python ui.facepile(["Ana", "Luis", "Kev", "Marta", "Sam"]) ``` ```python ui.facepile(["Ana", "Luis", "Kev", "Marta", "Sam", "Jo", "Lee"], max_shown=3) ``` ```python ui.facepile(["Ana", "Luis", "Kev", "Marta"], size=32, overlap=10) ``` #### Events Facepile has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.facepile` ```python facepile(people, *, size=22, overlap=6, max_shown=5, theme=None) ``` Overlapping collaborator avatars, as in the title bar of a collaborative editor. Those beyond `max_shown` are grouped into `+N`. | Property | Default | Description | | --- | --- | --- | | `people` | *required* | Initials or names. | | `size` | `22` | Size. | | `overlap` | `6` | Overlap in pixels. | | `max_shown` | `5` | How many to show. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#facepile) #### Related - [Avatar](https://albakore.github.io/pyzed/library/avatar/): A round avatar with initials in a collaborator color. - [Title bar](https://albakore.github.io/pyzed/library/title-bar/): The top bar with project and branch pickers. ### Field > A settings row: title and description left, control right. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/field/ :::tip[In plain words] A row of a form: the name of a setting on the left and its control on the right. ::: A form row like the ones of a settings screen: the title (and an optional description) on the left and any control on the right. Stack several in a column or a [Settings group](https://albakore.github.io/pyzed/library/settings-group/). `ui.field` · Category: [Forms](https://albakore.github.io/pyzed/library/#forms) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#field) **Code:** ```python pz.column([ ui.field("Autosave", ui.switch(True, on_toggle), description="Saves when you switch tabs"), ui.field("Format on save", ui.checkbox(False, on_toggle)), ui.field("Font size", ui.number_field(14, on_change, suffix="px")), ], spacing=14, width=440) ``` #### When to use - For preferences and forms where each control needs a label and maybe a hint. - It lines up switches, selects and number fields of different widths. #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ ui.field("Autosave", ui.switch(True, on_toggle), description="Saves when you switch tabs"), ui.field("Format on save", ui.checkbox(False, on_toggle)), ui.field("Font size", ui.number_field(14, on_change, suffix="px")), ], spacing=14, width=440) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Control ```python pz.container(ui.field("Autosave", ui.switch(True, on_toggle)), width=380) ``` ```python pz.container(ui.field("Font size", ui.number_field(14, on_change, suffix="px")), width=380) ``` ```python pz.container(ui.field("Theme", ui.select(["One Dark", "One Light"], "One Dark", on_select, width=150)), width=380) ``` ```python pz.container(ui.field("Name", ui.input("Pyzed", on_input, width=180)), width=380) ``` ##### Help and errors ```python pz.container(ui.field("Autosave", ui.switch(True, on_toggle), description="Saves when you switch tabs"), width=380) ``` ```python pz.container(ui.field("Port", ui.number_field(80, on_change), error="Ports below 1024 need admin rights"), width=380) ``` ##### States and events ```python pz.container(ui.field("Name", ui.input("", on_input, width=180), required=True), width=380) ``` ```python pz.container(ui.field("Email", ui.input("ada@", on_input, invalid=True), vertical=True, required=True, error="Enter a valid email"), width=320) ``` #### Events Field has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.field` ```python field( title, control, *, description=None, error=None, required=False, vertical=False, theme=None, ) ``` A form row: title and description on the left, control on the right (like a settings screen). | Property | Default | Description | | --- | --- | --- | | `title` | *required* | Title. | | `control` | *required* | The control (switch, input…). | | `description` | `None` | Help text. | | `error` | `None` | A validation message shown under the title in the error color (see `pz.validation_errors`). | | `required` | `False` | Adds a red `*` after the title. | | `vertical` | `False` | Puts the control under the title. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#field) #### Related - [Settings group](https://albakore.github.io/pyzed/library/settings-group/): A titled block of field rows, for settings screens. - [Switch](https://albakore.github.io/pyzed/library/switch/): An on/off switch for settings that apply at once. - [Number field](https://albakore.github.io/pyzed/library/number-field/): A number with −/+ buttons, limits, step and suffix. ### File picker > A path field with a button that opens the system's file or folder dialog. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/file-input/ :::tip[In plain words] A box with the location of a file and a button that opens the usual window to look for it. ::: `ui.file_input` shows a path and a browse button. The button opens the operating system's own dialog to open a file (`mode="open"`), several (`"open_many"`), a folder (`"folder"`) or to choose where to save (`"save"`), and `on_change` receives what the user chose: a path, or a list of paths with `open_many`. The path can also be typed or pasted. `filters` limits the file types (`"Images: png, jpg"`). `ui.file_input` · Category: [System](https://albakore.github.io/pyzed/library/#system) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#file_input) **Code:** ```python pz.column([ ui.field("Project folder", ui.file_input("~/projects/notes", on_change, mode="folder")), ui.field("Logo", ui.file_input("", on_change, filters="Images: png, jpg, svg", placeholder="Choose an image")), ui.field("Export to", ui.file_input("report.pdf", on_change, mode="save", button="Browse…")), ], spacing=12, width=420) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For settings that point to a file or folder: a project folder, a log file, an export target. - `button="Browse…"` shows text instead of the folder icon. - `ui.system.pick(then, mode=...)` returns the same dialog as a `Command`, for your own buttons. #### Usage ```python import pyzed as pz from pyzed import ui class Export(pz.App): def __init__(self): self.target = "" def view(self): return ui.file_input(self.target, lambda path: setattr(self, "target", path), mode="save", file_name="report.pdf", filters="PDF: pdf") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Mode ```python ui.file_input("~/notes/todo.md", on_change, width=320) ``` ```python ui.file_input(["a.png", "b.png"], on_change, mode="open_many", width=320) ``` ```python ui.file_input("~/projects", on_change, mode="folder", width=320) ``` ```python ui.file_input("report.pdf", on_change, mode="save", width=320) ``` ##### States ```python ui.file_input("", on_change, button="Browse…", width=320) ``` ```python ui.file_input("~/notes/todo.md", on_change, editable=False, width=320) ``` ```python ui.file_input("~/missing.txt", on_change, invalid=True, width=320) ``` ```python ui.file_input("~/notes/todo.md", on_change, disabled=True, width=320) ``` #### Events File picker has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_change` | `ui.file_input`, `ui.path_input` | `(value)` | Receives the path (a list with `"open_many"`). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Export(pz.App): def __init__(self): self.folder = "" def chosen(self, path): # on_change: the path (a list with mode="open_many") self.folder = path def view(self): return pz.column([ ui.file_input(self.folder, self.chosen, mode="folder", placeholder="Choose a folder"), ui.label(f"Saving to {self.folder or '…'}"), ], spacing=8, width=360) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Chosen: path: str class Export(pz.App): path = "" def update(self, message): match message: case Chosen(path): self.path = path def view(self): return ui.file_input(self.path, lambda path: Chosen(path), mode="save", file_name="report.pdf") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: image: str = "" def view(state, set_state): return ui.file_input(state.image, lambda path: set_state(image=path), filters="Images: png, jpg") ``` #### Properties and API ##### `ui.file_input` ```python file_input( value, on_change=None, *, mode='open', filters=None, title=None, directory=None, file_name='', placeholder=None, button=None, editable=True, disabled=False, invalid=False, id=None, width='fill', theme=None, ) ``` A path field with a button that opens the system's file dialog, so nobody types a path by hand. See the [File picker](https://albakore.github.io/pyzed/library/file-input/) page. | Property | Default | Description | | --- | --- | --- | | `value` | *required* | Current value. | | `mode` | `"open"` | `"open"` (a file), `"open_many"` (a list), `"save"` or `"folder"`. | | `filters` | `None` | Files shown: `{"Images": "png jpg"}` or `"Images: png, jpg"`. | | `title` | `None` | The dialog's title. | | `directory` | `None` | Where the dialog opens (default: the folder of the current path). | | `file_name` | `""` | The name suggested when saving. | | `placeholder` | `None` | Hint text shown when empty. | | `button` | `None` | Text for the button instead of a folder icon. | | `editable` | `True` | `False` keeps the path from being typed. | | `disabled` | `False` | Disables it (ignores clicks). | | `invalid` | `False` | Paints the border in the error color. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `width` | `"fill"` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_change` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#file_input) ##### `ui.path_input` ```python path_input( value, on_change=None, *, folder=False, save=False, filters=None, kind=None, directory=None, relative_to=None, title=None, placeholder=None, size='md', mono=True, disabled=False, invalid=False, theme=None, ) ``` A text field for a file or folder path with a button that opens the system's file dialog, so the path never has to be typed (it still can be). | Property | Default | Description | | --- | --- | --- | | `value` | *required* | Current path. | | `folder` | `False` | Picks a folder instead of a file. | | `save` | `False` | Shows the "Save as" dialog. | | `filters` | `None` | `(name, extensions)` pairs: `[("Images", ["png", "jpg"])]`. | | `kind` | `None` | Common filters by name: `"image"`, `"audio"`, `"video"`, `"font"`, `"shader"` or `"data"`. | | `directory` | `None` | Folder the dialog opens in (by default, the current path's). | | `relative_to` | `None` | A chosen path inside this folder is given relative to it. | | `title` | `None` | Title of the dialog. | | `placeholder` | `None` | Text shown while it is empty. | | `size` | `"md"` | `"sm"`, `"md"` or `"lg"`. | | `mono` | `True` | Monospaced text. | | `disabled` | `False` | Greys it out. | | `invalid` | `False` | Paints the border in the error color. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_change` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#path_input) ##### `ui.system.pick` ```python pick(then, *, mode='open', title=None, filters=None, directory=None, file_name='') ``` The system's file dialog as a `Command`: return it from a callback and `then` receives what the user chose (a path, a list of paths with `"open_many"`, or `None` when they cancel). `ui.file_input` uses it. | Property | Default | Description | | --- | --- | --- | | `then` | *required* | Called with the result. | | `mode` | `"open"` | `"open"`, `"open_many"`, `"save"` or `"folder"`. | | `title` | `None` | The dialog's title. | | `filters` | `None` | Files shown: `{"Images": "png jpg"}` or `"Images: png, jpg"`. | | `directory` | `None` | Where the dialog opens. | | `file_name` | `""` | The name suggested when saving. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#pick) #### Related - [Drop zone](https://albakore.github.io/pyzed/library/drop-zone/): An area that takes files dragged from the desktop or the file manager. - [Input](https://albakore.github.io/pyzed/library/input/): A controlled text field with icon, placeholder and password mode. - [Field](https://albakore.github.io/pyzed/library/field/): A settings row: title and description left, control right. ### Flex > CSS flexbox: justify, align, gap, wrap and grow. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/flex/ :::tip[In plain words] Spreads things along a line: packed together, evenly spaced, or with one that grows. ::: Lays children out along one axis like CSS flexbox: `justify` on the main axis (`start`, `center`, `end`, `between`, `around`, `evenly`), `align` on the cross axis, `gap` and `wrap`. `pz.flex_item(child, grow=, basis=)` makes a child grow or gives it a base size. `pz.flex` · Category: [Layout](https://albakore.github.io/pyzed/library/#layout) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#flex) **Code:** ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.column([ pz.flex([box("A"), box("B"), box("C")], justify="between", width=440), pz.flex([box("fixed"), pz.flex_item(box("grows", w="fill"), grow=1), box("fixed")], gap=8, width=440), pz.flex([box("A"), box("B")], justify="center", gap=8, width=440), ], spacing=14) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - When `row`/`column` are not enough: even distribution, growing items, wrapping cards. #### Usage ```python import pyzed as pz from pyzed import ui box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.column([ pz.flex([box("A"), box("B"), box("C")], justify="between", width=440), pz.flex([box("fixed"), pz.flex_item(box("grows", w="fill"), grow=1), box("fixed")], gap=8, width=440), pz.flex([box("A"), box("B")], justify="center", gap=8, width=440), ], spacing=14) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Justify ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.flex([box("A"), box("B")], justify="start", gap=8, width=360) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.flex([box("A"), box("B")], justify="center", gap=8, width=360) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.flex([box("A"), box("B")], justify="end", gap=8, width=360) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.flex([box("A"), box("B"), box("C")], justify="between", width=360) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.flex([box("A"), box("B"), box("C")], justify="around", width=360) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.flex([box("A"), box("B"), box("C")], justify="evenly", width=360) ``` ##### Grow ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.flex([box("fixed"), pz.flex_item(box("grows", w="fill"), grow=1), box("fixed")], gap=8, width=360) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.flex([box(str(i)) for i in range(1, 7)], gap=8, wrap=True, width=300) ``` #### Events Flex has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.flex` ```python flex( children=(), *, direction='row', justify='start', align='start', gap=0, wrap=False, padding=None, width=None, height=None, ) ``` Lays children out along one axis, like CSS flexbox, with `justify` on the main axis and `align` on the cross axis. Use `pz.flex_item` to make a child grow or give it a fixed size. | Property | Default | Description | | --- | --- | --- | | `children` | `()` | The widgets, or `pz.flex_item(...)` for children with their own sizing. | | `direction` | `"row"` | `"row"` or `"column"`. | | `justify` | `"start"` | `"start"`, `"center"`, `"end"`, `"between"`, `"around"` or `"evenly"`. No effect when a child grows. | | `align` | `"start"` | Cross-axis alignment: `"start"`, `"center"` or `"end"`. | | `gap` | `0` | Space between children. | | `wrap` | `False` | Wraps onto new lines (rows with `justify="start"` only). | | `padding` | `None` | Space around the children. | | `width` | `None` | Width. | | `height` | `None` | Height. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#flex) ##### `pz.flex_item` ```python flex_item(content, *, grow=1, basis=None, align=None) ``` Sizes a child of `pz.flex`. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | The widget. | | `grow` | `1` | Share of the free space on the main axis (`0` keeps its natural size). | | `basis` | `None` | A fixed main size in pixels, instead of growing. | | `align` | `None` | Cross-axis alignment for this child. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#flex_item) #### Related - [Grid](https://albakore.github.io/pyzed/library/grid/): Equal columns, or CSS-like tracks with spans. - [Row](https://albakore.github.io/pyzed/library/row/): Lays out children horizontally. ### Grid > Equal columns, or CSS-like tracks with spans. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/grid/ :::tip[In plain words] Arranges things in rows and columns, like tiles on a wall. ::: Lays out children in a grid. With `columns=3` the columns are equal, and `max_width` fits as many as possible. With track lists (`columns=[200, "1fr", "auto"]`) it works like a CSS grid, and `pz.cell(child, column=, row=, column_span=, row_span=)` places a child explicitly. `pz.grid` · Category: [Layout](https://albakore.github.io/pyzed/library/#layout) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#grid) **Code:** ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.grid([box(str(i), w="fill") for i in range(1, 9)], columns=4, spacing=8), width=440) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For galleries, dashboards and page layouts with a header, sidebar and content. #### Usage ```python import pyzed as pz from pyzed import ui box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.grid([box(str(i), w="fill") for i in range(1, 9)], columns=4, spacing=8), width=440) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Columns ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.grid([box(str(i), w="fill") for i in range(1, 5)], columns=2, spacing=8, height=44), width=220) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.grid([box(str(i), w="fill") for i in range(1, 7)], columns=3, spacing=8, height=44), width=300) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.grid([box(str(i), w="fill") for i in range(1, 9)], columns=4, spacing=8, height=44), width=380) ``` ##### Tracks ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.grid([box("100 px", w="fill"), box("1fr", w="fill")], columns=[100, "1fr"], spacing=8), width=340, height=44) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.grid([pz.cell(box("header", w="fill"), column=0, row=0, column_span=2), pz.cell(box("a", w="fill"), column=0, row=1), pz.cell(box("b", w="fill"), column=1, row=1)], columns=["1fr", "1fr"], spacing=8), width=300, height=96) ``` #### Examples ##### Tracks and spans Numbers are pixels, `"1fr"` shares the free space and `"auto"` fits the content. **Code:** ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.grid([ pz.cell(box("header", w="fill"), column=0, row=0, column_span=2), pz.cell(box("sidebar", w="fill", h="fill"), column=0, row=1), pz.cell(box("content", w="fill", h="fill"), column=1, row=1), ], columns=[120, "1fr"], rows=[44, 110], spacing=8), width=440) ``` #### Events Grid has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.grid` ```python grid( children=None, *, columns=None, rows=None, max_width=None, spacing=0.0, row_spacing=None, height=None, aspect_ratio=None, width=None, padding=None, align_x=None, align_y=None, ) ``` Lays out its children in a grid. With `columns=3` the columns are equal (or `max_width` fits as many as possible). With track lists (`columns=[200, "1fr", "auto"]`, `rows=...`) it works like a CSS grid: numbers are pixels, `"auto"` fits the content and `"fr"` shares the space left. Wrap children in `pz.cell` to place them and make them span; the rest fill the free cells row by row. See [Layout](https://albakore.github.io/pyzed/guides/layout/#grids). | Property | Default | Description | | --- | --- | --- | | `children` | `None` | List of children. Nested lists are flattened and `None` and `False` are ignored, so you can write `cond and widget`. | | `columns` | `None` | Number of equal columns, or tracks: a list (`[200, "1fr", "auto"]`) or a string (`"200 1fr auto"`). | | `rows` | `None` | Row tracks, like `columns`. Rows beyond the list are `"auto"`. | | `max_width` | `None` | Fits as many columns of at most this width as possible (`columns=` only). | | `spacing` | `0.0` | Space between cells. | | `row_spacing` | `None` | Space between rows, if different. | | `height` | `None` | With `columns=`: height of each row. With tracks: the grid's height. | | `aspect_ratio` | `None` | Keeps cells at this width/height ratio (`columns=` only). | | `width` | `None` | With `columns=`: pixels. With tracks: the grid's width (default `"fill"`). | | `padding` | `None` | Space around the cells. | | `align_x` | `None` | Horizontal alignment of items in their cells: `"start"`, `"center"`, `"end"`. | | `align_y` | `None` | Vertical alignment of items in their cells. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#grid) ##### `pz.cell` ```python cell( content, *, column=None, row=None, column_span=1, row_span=1, align_x=None, align_y=None, ) ``` Places a child in a track grid: its column and row (from 0) and how many it spans. Children without a cell fill the free cells row by row. Outside a grid it is just the child. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | The widget. | | `column` | `None` | Column index (from 0). | | `row` | `None` | Row index (from 0). | | `column_span` | `1` | Columns it covers. | | `row_span` | `1` | Rows it covers. | | `align_x` | `None` | Horizontal alignment in the cell. | | `align_y` | `None` | Vertical alignment in the cell. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#cell) #### Related - [Flex](https://albakore.github.io/pyzed/library/flex/): CSS flexbox: justify, align, gap, wrap and grow. - [Row](https://albakore.github.io/pyzed/library/row/): Lays out children horizontally. - [Column](https://albakore.github.io/pyzed/library/column/): Stacks children vertically. ### Heading > Semibold titles in three levels. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/heading/ :::tip[In plain words] A title: bigger, bolder text that names a page or a section. ::: A semibold title. `level=1` (default), `2` or `3` pick the size, so headings stay consistent across screens. `ui.heading` · Category: [Display](https://albakore.github.io/pyzed/library/#display) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#heading) **Code:** ```python pz.column([ ui.heading("Heading 1"), ui.heading("Heading 2", level=2), ui.heading("Heading 3", level=3), ui.muted("Body text below the headings."), ], spacing=6) ``` #### When to use - For the title of a page, a dialog section or a settings group. - For a small uppercase list title, use [List header](https://albakore.github.io/pyzed/library/list-header/). #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ ui.heading("Heading 1"), ui.heading("Heading 2", level=2), ui.heading("Heading 3", level=3), ui.muted("Body text below the headings."), ], spacing=6) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Level ```python ui.heading("Project settings") ``` ```python ui.heading("Project settings", level=2) ``` ```python ui.heading("Project settings", level=3) ``` ```python ui.heading("Project settings", level=4) ``` ##### Color ```python ui.heading("Welcome back", level=2, color="accent") ``` ```python pz.column([ui.heading("Billing", level=2), ui.muted("Invoices and payment methods.")], spacing=4) ``` #### Events Heading has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.heading` ```python heading(content, *, level=1, theme=None, **kwargs) ``` A semibold heading. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `level` | `1` | 1 (26 px), 2 (20 px), 3 (16 px) or 4 (13.5 px). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | | `**kwargs` | — | Same as `label`. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#heading) #### Related - [Label](https://albakore.github.io/pyzed/library/label/): Text with a theme color, size and weight; `muted` for secondary text. - [Card](https://albakore.github.io/pyzed/library/card/): A bordered surface with an optional title and actions. ### Icon > Lucide icons by name, and SVG images. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/icon/ :::tip[In plain words] Small pictures (a folder, a bell, a gear) from a library of more than 1,500. ::: `pz.icon(name)` draws one of the 1,500+ [Lucide](https://lucide.dev) icons; `color` defaults to the surrounding text color. `pz.svg(source)` draws any SVG from a path or bytes, tinted with `color` if you want. `pz.icon` · Category: [Content](https://albakore.github.io/pyzed/library/#content) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#icon) **Code:** ```python pz.row([ pz.icon("sparkles", size=28, color="#e5c07b"), pz.icon("git-branch", size=28, color="#a1c181"), pz.icon("folder-open", size=28, color="#74ade8"), pz.icon("bug", size=28, color="#d07277"), pz.icon("terminal", size=28, color="#c678dd"), pz.svg("logo.svg", width=40, height=40), ], spacing=20, align="center") ``` #### When to use - Inside buttons, list rows and headers. Run `pyzed icons` to search the names. #### Usage ```python import pyzed as pz pz.row([ pz.icon("sparkles", size=28, color="#e5c07b"), pz.icon("git-branch", size=28, color="#a1c181"), pz.icon("folder-open", size=28, color="#74ade8"), pz.icon("bug", size=28, color="#d07277"), pz.icon("terminal", size=28, color="#c678dd"), pz.svg("logo.svg", width=40, height=40), ], spacing=20, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Size ```python pz.icon("sparkles", size=12) ``` ```python pz.icon("sparkles", size=16) ``` ```python pz.icon("sparkles", size=24) ``` ```python pz.icon("sparkles", size=40) ``` ##### Color ```python pz.icon("git-branch", size=24, color="#a1c181") ``` ```python pz.icon("bug", size=24, color="#d07277") ``` ```python pz.icon("folder-open", size=24, color="#74ade8") ``` ##### SVG `color` paints every visible pixel of the SVG in one color and keeps the transparent ones, like an icon tint. An SVG with a filled background, such as `logo.svg`, becomes a plain tile. ```python pz.svg("logo.svg", width=48, height=48) ``` ```python shapes = ('' '') pz.svg(shapes, width=48, height=48, color="#e5c07b") ``` #### Events Icon has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.icon` ```python icon(name, *, size=16, color=None) ``` A [Lucide](https://lucide.dev) icon. `color` defaults to the surrounding text color. | Property | Default | Description | | --- | --- | --- | | `name` | *required* | Icon name (`pyzed icons` lists them). | | `size` | `16` | Size in pixels. | | `color` | `None` | Color. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#icon) ##### `pz.svg` ```python svg( source, *, width=None, height=None, color=None, content_fit=None, opacity=1.0, rotation=0.0, ) ``` An SVG image. | Property | Default | Description | | --- | --- | --- | | `source` | *required* | Path to an `.svg`, the SVG code as a string (starting with `<`) or `bytes`. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `color` | `None` | If given, tints the whole SVG with that color (useful for monochrome icons). | | `content_fit` | `None` | `"contain"`, `"cover"`, `"fill"`, `"none"` or `"scale-down"`. | | `opacity` | `1.0` | Opacity from 0 to 1. | | `rotation` | `0.0` | Rotation in degrees. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#svg) #### Related - [Icon button](https://albakore.github.io/pyzed/library/icon-button/): A square button with just an icon and an optional tooltip. - [Image](https://albakore.github.io/pyzed/library/image/): Bitmaps with fit, opacity, radius; a pan-and-zoom viewer. ### Icon button > A square button with just an icon and an optional tooltip. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/icon-button/ :::tip[In plain words] A small button with just a picture (a magnifying glass, a gear) instead of words. ::: A compact square button that shows a [Lucide](https://lucide.dev) icon. It is ghost by default, so it fits in toolbars, panel headers and tab bars. `tooltip=` adds a tooltip on hover. `ui.icon_button` · Category: [Actions](https://albakore.github.io/pyzed/library/#actions) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#icon_button) **Code:** ```python pz.row([ ui.icon_button("search", on_search, tooltip="Search"), ui.icon_button("settings", on_settings, tooltip="Settings"), ui.icon_button("bell", on_notifications, selected=True), ui.icon_button("plus", on_new, variant="filled"), ], spacing=6) ``` #### When to use - For frequent actions whose icon is obvious (search, settings, close, add). - Always give it a `tooltip` when the icon alone may be ambiguous. - `selected=True` shows a toggled state (a panel that is open, a filter that is on). #### Usage ```python import pyzed as pz from pyzed import ui pz.row([ ui.icon_button("search", on_search, tooltip="Search"), ui.icon_button("settings", on_settings, tooltip="Settings"), ui.icon_button("bell", on_notifications, selected=True), ui.icon_button("plus", on_new, variant="filled"), ], spacing=6) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Size ```python ui.icon_button("star", on_press, size="xs") ``` ```python ui.icon_button("star", on_press, size="sm") ``` ```python ui.icon_button("star", on_press, size="md") ``` ```python ui.icon_button("star", on_press, size="lg") ``` ##### Variant ```python ui.icon_button("settings", on_press) ``` ```python ui.icon_button("settings", on_press, variant="filled") ``` ```python ui.icon_button("settings", on_press, variant="outline") ``` ```python ui.icon_button("settings", on_press, variant="solid") ``` ```python ui.icon_button("settings", on_press, variant="tinted") ``` ##### Color ```python ui.icon_button("sparkles", on_press, color="accent") ``` ```python ui.icon_button("circle-check", on_press, color="success") ``` ```python ui.icon_button("triangle-alert", on_press, color="warning") ``` ```python ui.icon_button("trash-2", on_press, color="error", variant="outline") ``` ##### State Drawn as the pointer shows it: tooltips only open on hover. ```python ui.icon_button("panel-left", on_press, selected=True) ``` ```python ui.icon_button("lock", on_press, disabled=True) ``` ```python ui.icon_button("search", on_press, tooltip="Search") ``` ##### States and events ```python ui.icon_button("bell", on_press, indicator="accent") ``` ```python ui.icon_button("trash-2", on_press, tint="error") ``` ```python ui.icon_button("refresh-cw", on_press, loading=True) ``` ```python ui.icon_button("search", on_press, tooltip="Search", keys="ctrl-f") ``` #### Events Icon button has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `()` | Message or callable sent on press. `None` disables the control. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Toolbar(pz.App): def __init__(self): self.bold = False def toggle_bold(self): self.bold = not self.bold def view(self): return pz.row([ ui.icon_button("bold", self.toggle_bold, selected=self.bold, tooltip="Bold", keys="ctrl-b"), ui.icon_button("trash-2", self.clear, tooltip="Clear", disabled=not self.bold), ], spacing=4) def clear(self): self.bold = False ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class ToggleBold: pass class Toolbar(pz.App): bold = False def update(self, message): if isinstance(message, ToggleBold): self.bold = not self.bold def view(self): return ui.icon_button("bold", ToggleBold(), selected=self.bold, tooltip="Bold") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: bold: bool = False def view(state, set_state): return ui.icon_button("bold", lambda: set_state(bold=not state.bold), selected=state.bold, tooltip="Bold") ``` #### Tips :::tip Run `pyzed icons` to search the icon names. ::: #### Properties and API ##### `ui.icon_button` ```python icon_button( name, on_press=None, *, size='md', variant='ghost', color=None, selected=False, disabled=False, tooltip=None, keys=None, tint=None, loading=False, indicator=None, theme=None, ) ``` A square button with just an icon. | Property | Default | Description | | --- | --- | --- | | `name` | *required* | Icon name. | | `size` | `"md"` | `"xs"`, `"sm"`, `"md"` or `"lg"`. | | `variant` | `"ghost"` | As in `ui.button`. Defaults to `"ghost"`. | | `color` | `None` | Icon color. | | `selected` | `False` | Marks it as selected. | | `disabled` | `False` | Disables it (ignores clicks). | | `tooltip` | `None` | Tooltip text. | | `keys` | `None` | Key binding shown in the tooltip. | | `tint` | `None` | Colors it (`"error"`, `"accent"`…). | | `loading` | `False` | Swaps the icon for a spinner and ignores presses. | | `indicator` | `None` | Adds a small dot in this color at the top right (unread, changes…). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#icon_button) #### Related - [Button](https://albakore.github.io/pyzed/library/button/): The themed button: variants, sizes, icons and shortcuts. - [Tooltip](https://albakore.github.io/pyzed/library/tooltip/): A hint shown on hover, optionally with its shortcut. - [Toolbar](https://albakore.github.io/pyzed/library/toolbar/): The bar under the tabs: breadcrumbs and buffer actions. ### Icon picker > Pick one of the ~2000 Lucide icons from a searchable grid. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/icon-picker/ :::tip[In plain words] A searchable grid of little pictures to choose an icon from. ::: `ui.IconPicker` is a component with a search box, a category drop-down and a grid of every bundled Lucide icon. The search matches names and tags ("person" finds `user`), Enter picks the first match and `on_change` receives the icon's name in `event.value`. `ui.icon_picker_dialog` puts it in a dialog that picks on a click, and `ui.icon_grid` is the bare grid, which only builds the rows in view. `ui.IconPicker` · Category: [Forms](https://albakore.github.io/pyzed/library/#forms) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#iconpicker) **Code:** ```python ui.IconPicker(value="rocket", columns=10, height=200, clearable=True, on_change=on_change) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - To let users choose an icon for a folder, a tag, a shortcut or a toolbar button. - Show the current icon as a button and open `icon_picker_dialog` in a [Dialog layer](https://albakore.github.io/pyzed/library/dialog-layer/) when it is pressed. #### Usage ```python import pyzed as pz from pyzed import ui class Shortcuts(pz.App): def __init__(self): self.icon = "rocket" self.picking = False def pick(self, name): self.icon, self.picking = name or "circle-dashed", False def view(self): page = ui.button("Change icon", lambda: setattr(self, "picking", True), icon=self.icon) dialog = ui.icon_picker_dialog(self.icon, self.pick, on_close=lambda: setattr(self, "picking", False)) return ui.dialog_layer(page, dialog if self.picking else None, on_dismiss=lambda: setattr(self, "picking", False)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Picker ```python ui.IconPicker(value="rocket", columns=8, height=180, on_change=on_change) ``` ```python ui.IconPicker(value="heart", columns=8, height=180, clearable=True, on_change=on_change) ``` ##### Building blocks ```python ui.icon_grid(pz.icons.search("arrow")[:24], on_pick, selected="arrow-right", columns=8, height=110) ``` ```python ui.icon_picker_dialog("rocket", on_pick, on_close=on_close, columns=8) ``` #### Events Icon picker has **3 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_change` | `ui.IconPicker` | `(event)` | Receives `event.value`. | | `on_pick` | `ui.icon_picker_dialog`, `ui.icon_grid` | `(name)` | Called with the clicked icon's name (`""` when cleared). | | `on_close` | `ui.icon_picker_dialog` | `()` | The close button. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Shortcut(pz.App): def __init__(self): self.icon = "rocket" self.picking = False def pick(self, name): # on_pick: the icon's name ("" when cleared) self.icon, self.picking = name or "circle-dashed", False def view(self): page = ui.button("Change icon", lambda: setattr(self, "picking", True), icon=self.icon) dialog = ui.icon_picker_dialog(self.icon, self.pick, on_close=lambda: setattr(self, "picking", False)) return ui.dialog_layer(page, dialog if self.picking else None, on_dismiss=lambda: setattr(self, "picking", False)) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Icon: name: str class Shortcut(pz.App): icon = "rocket" def update(self, message): match message: case Icon(name): self.icon = name or "circle-dashed" def view(self): # IconPicker is a pz.Component: its handler gets a pz.Event return ui.IconPicker(value=self.icon, height=200, on_change=lambda e: Icon(e.value)) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: icon: str = "rocket" def view(state, set_state): return pz.column([ ui.icon_grid(["rocket", "star", "heart", "bell"], lambda name: set_state(icon=name), selected=state.icon, columns=4, height=60), ui.button("Launch", None, icon=state.icon), ], spacing=8) ``` #### Properties and API ##### `ui.IconPicker` ```python class IconPicker ``` A component that picks a Lucide icon: a search box (names and tags), a category drop-down and a grid that only builds the rows in view. Enter picks the first match. `on_change` gets the icon's name (`""` when cleared); pass it back as `value`. See the [Icon picker](https://albakore.github.io/pyzed/library/icon-picker/) page. | Property | Default | Description | | --- | --- | --- | | `value` | `""` | The picked icon's name. | | `columns` | `8` | Icons per row. | | `height` | `288` | Height of the grid. | | `clearable` | `False` | Shows a button that clears the icon. | | `autofocus` | `False` | Focuses the search box when it appears. | Events: `on_change` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#iconpicker) ##### `ui.icon_picker_dialog` ```python icon_picker_dialog( value, on_pick, *, on_close=None, title=None, columns=10, clearable=True, key='icon-picker', theme=None, ) ``` A dialog with an `IconPicker` that picks on a click; use it as the dialog of `ui.dialog_layer`. The search box gets the focus. | Property | Default | Description | | --- | --- | --- | | `value` | *required* | The current icon. | | `title` | `None` | Default: "Choose an icon", translated. | | `columns` | `10` | Icons per row. | | `clearable` | `True` | Shows the "No icon" button. | | `key` | `"icon-picker"` | Component key, for several pickers in one view. | | `theme` | `None` | Theme. | Events: `on_pick`, `on_close` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#icon_picker_dialog) ##### `ui.icon_grid` ```python icon_grid( names, on_pick, *, selected=None, columns=8, cell=34, height=288, id=None, theme=None, ) ``` The bare grid of icons, virtualized: only the rows in view are built, so thousands of icons cost the same as a few. | Property | Default | Description | | --- | --- | --- | | `names` | *required* | Icon names, in order. | | `selected` | `None` | The highlighted name. | | `columns` | `8` | Icons per row. | | `cell` | `34` | Side of each cell in pixels. | | `height` | `288` | Height of the grid. | | `id` | `None` | Id of the scrollable, for `Command.scroll_to`. | | `theme` | `None` | Theme. | Events: `on_pick` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#icon_grid) ##### `pz.icons.search` ```python search(query, among=None) ``` Icons matching a search by name and tag, best first: exact names, then names that start with the query, names with every word and icons found by their tags (`search("person")` finds `user`). | Property | Default | Description | | --- | --- | --- | | `query` | *required* | Words that must all appear in the name or the tags. | | `among` | `None` | Only search these names (default: every icon). | [Full reference →](https://albakore.github.io/pyzed/reference/icons/#search) ##### `pz.icons.category` ```python category(key, among=None) ``` The icons of a category of `CATEGORIES`, sorted. An icon can be in several. | Property | Default | Description | | --- | --- | --- | | `key` | *required* | A key of `CATEGORIES` (`"arrows"`, `"files"`, `"people"`...). | | `among` | `None` | Only look at these names. | [Full reference →](https://albakore.github.io/pyzed/reference/icons/#category) #### Related - [Icon](https://albakore.github.io/pyzed/library/icon/): Lucide icons by name, and SVG images. - [Dialog layer](https://albakore.github.io/pyzed/library/dialog-layer/): Centers a dialog over your view with a dimmed backdrop. - [Color picker](https://albakore.github.io/pyzed/library/color-picker/): Pick a color, a gradient or a masked fill; swatches show them. ### Image > Bitmaps with fit, opacity, radius; a pan-and-zoom viewer. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/image/ :::tip[In plain words] Shows a picture from a file: a photo, a logo, a screenshot. ::: `pz.image(source)` shows a PNG, JPEG, GIF, WebP, BMP… from a path, `bytes`, or raw RGBA pixels with `size=(w, h)`. Options: `content_fit` (`"contain"`, `"cover"`, `"fill"`, `"none"`, `"scale_down"`), `filter` (`"linear"` or `"nearest"`), `opacity`, `radius`, `rotation` and `scale`. `pz.image_viewer` adds pan (drag) and zoom (wheel). `pz.image` · Category: [Content](https://albakore.github.io/pyzed/library/#content) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#image) **Code:** ```python pz.row([ pz.image("photo.png", width=300, height=180, content_fit="cover", radius=10), pz.image("photo.png", width=140, height=180, content_fit="contain", opacity=0.5), ], spacing=16, align="center") ``` #### When to use - For screenshots, avatars, thumbnails and photo viewers. #### Usage ```python import pyzed as pz pz.row([ pz.image("photo.png", width=300, height=180, content_fit="cover", radius=10), pz.image("photo.png", width=140, height=180, content_fit="contain", opacity=0.5), ], spacing=16, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Fit ```python pz.image("photo.png", width=200, height=110, content_fit="cover") ``` ```python pz.image("photo.png", width=200, height=110, content_fit="contain") ``` ```python pz.image("photo.png", width=200, height=110, content_fit="fill") ``` ##### Look `rotation` is in degrees, clockwise; the corners of a rotated image may reach outside its box. ```python pz.image("photo.png", width=200, height=110, content_fit="cover", radius=16) ``` ```python pz.image("photo.png", width=200, height=110, content_fit="cover", opacity=0.4) ``` ```python pz.image("photo.png", width=200, height=110, content_fit="cover", radius=10, rotation=8) ``` #### Events Image has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.image` ```python image( source, *, width=None, height=None, content_fit=None, filter='linear', opacity=1.0, radius=0.0, rotation=0.0, scale=1.0, size=None, ) ``` A bitmap image (PNG, JPEG, GIF, BMP, WebP…) from a path or `bytes`, or raw RGBA pixels. | Property | Default | Description | | --- | --- | --- | | `source` | *required* | File path, `bytes` of the encoded file, or raw RGBA pixels with `size=(width, height)`. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `content_fit` | `None` | `"contain"`, `"cover"`, `"fill"`, `"none"` or `"scale-down"`. | | `filter` | `"linear"` | `"linear"` (smooth) or `"nearest"` (crisp pixels, for pixel art). | | `opacity` | `1.0` | Opacity from 0 to 1. | | `radius` | `0.0` | Corner radius. | | `rotation` | `0.0` | Rotation in degrees. | | `scale` | `1.0` | Scale. | | `size` | `None` | `(width, height)` when `source` is raw RGBA pixels. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#image) ##### `pz.image_viewer` ```python image_viewer( source, *, width=None, height=None, min_scale=0.25, max_scale=10.0, scale_step=0.1, filter='linear', size=None, ) ``` An image you can pan (by dragging) and zoom (mouse wheel), like Iced's viewer. | Property | Default | Description | | --- | --- | --- | | `source` | *required* | File path, `bytes` of the encoded file, or raw RGBA pixels with `size=(width, height)`. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `min_scale` | `0.25` | Minimum zoom. | | `max_scale` | `10.0` | Maximum zoom. | | `scale_step` | `0.1` | How much the zoom changes per wheel step. | | `filter` | `"linear"` | `"linear"` (smooth) or `"nearest"` (crisp pixels, for pixel art). | | `size` | `None` | `(width, height)` for raw RGBA pixels. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#image_viewer) #### Related - [Icon](https://albakore.github.io/pyzed/library/icon/): Lucide icons by name, and SVG images. - [QR code](https://albakore.github.io/pyzed/library/qr-code/): A QR code for any text or URL. ### Indicator > A colored dot for status, presence or unsaved changes. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/indicator/ :::tip[In plain words] A small colored dot that tells a state at a glance: green is fine, red is a problem. ::: A small colored dot. `color` is a theme token or a hex color and `size` its diameter. `ui.indicator` · Category: [Display](https://albakore.github.io/pyzed/library/#display) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#indicator) **Code:** ```python pz.column([ pz.row([ui.indicator("success"), ui.label("Server running")], spacing=8, align="center"), pz.row([ui.indicator("warning"), ui.label("Reconnecting")], spacing=8, align="center"), pz.row([ui.indicator("error"), ui.label("Build failed")], spacing=8, align="center"), pz.row([ui.indicator(size=10), ui.label("Unsaved changes")], spacing=8, align="center"), ], spacing=10) ``` #### When to use - Next to a name to show presence (online, busy) or a state (running, failed). - On a tab or list item to mark unsaved changes. #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ pz.row([ui.indicator("success"), ui.label("Server running")], spacing=8, align="center"), pz.row([ui.indicator("warning"), ui.label("Reconnecting")], spacing=8, align="center"), pz.row([ui.indicator("error"), ui.label("Build failed")], spacing=8, align="center"), pz.row([ui.indicator(size=10), ui.label("Unsaved changes")], spacing=8, align="center"), ], spacing=10) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Color ```python ui.indicator() ``` ```python ui.indicator("success") ``` ```python ui.indicator("warning") ``` ```python ui.indicator("error") ``` ```python ui.indicator("text_muted") ``` ```python ui.indicator("#c678dd") ``` ##### Size ```python ui.indicator("success", size=6) ``` ```python ui.indicator("success", size=10) ``` ```python ui.indicator("success", size=14) ``` ##### Next to text ```python pz.row([ui.indicator("success"), ui.label("Ana is online")], spacing=8, align="center") ``` ```python pz.row([ui.label("notes.py"), ui.indicator(size=8)], spacing=6, align="center") ``` #### Events Indicator has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.indicator` ```python indicator(color='accent', *, size=6, theme=None) ``` A colored dot (status, unsaved changes, presence). | Property | Default | Description | | --- | --- | --- | | `color` | `"accent"` | Token or color. | | `size` | `6` | Diameter. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#indicator) #### Related - [Badge](https://albakore.github.io/pyzed/library/badge/): A small pill for statuses, versions and counters. - [Avatar](https://albakore.github.io/pyzed/library/avatar/): A round avatar with initials in a collaborator color. ### Input > A controlled text field with icon, placeholder and password mode. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/input/ :::tip[In plain words] A box where people type one line of text: a name, an email, a password. ::: A themed single-line text field. It is **controlled**: it shows `value` and reports every keystroke to `on_input`, so you store the text in your state and pass it back in `view()`. `on_submit` runs on Enter. `ui.input` · Category: [Forms](https://albakore.github.io/pyzed/library/#forms) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#input) **Code:** ```python pz.column([ ui.input("", on_input, placeholder="Project name"), ui.input("ada@example.com", on_input, icon="mail"), ui.input("hunter2", on_input, secure=True, icon="lock"), ], spacing=10, width=360) ``` #### When to use - For names, paths, search boxes, emails and passwords (`secure=True`). - For multi-line text or code use [Editor](https://albakore.github.io/pyzed/library/editor/). - Give it an `id` to focus it from code with `pz.Command.focus(id)`. #### Usage ```python import pyzed as pz from pyzed import ui class Form(pz.App): def __init__(self): self.name = "" def view(self): return ui.input(self.name, lambda text: setattr(self, "name", text), placeholder="Project name", on_submit=self.create, id="name") def on_start(self): return pz.Command.focus("name") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python ui.input("", on_input, placeholder="Project name", width=260) ``` ```python ui.input("Pyzed", on_input, width=260) ``` ```python ui.input("ada@example.com", on_input, icon="mail", width=260) ``` ```python ui.input("hunter2", on_input, secure=True, icon="lock", width=260) ``` ##### Size ```python ui.input("Small", on_input, size="sm", width=260) ``` ```python ui.input("Medium", on_input, size="md", width=260) ``` ```python ui.input("Large", on_input, size="lg", width=260) ``` ##### Style ```python ui.input("Borderless", on_input, borderless=True, width=260) ``` ```python ui.input("SELECT * FROM users", on_input, mono=True, width=260) ``` ```python ui.input("Can't edit me", width=260) ``` ##### Validation Show errors with [Field](https://albakore.github.io/pyzed/library/field/)'s `error=`, next to the input. ```python ui.field("Email", ui.input("ada@", on_input, width=220), error="Enter a valid email") ``` ##### States and events Focus, blur and keys come from the common events: `.on(focus=..., blur=..., key_down=...)`. ```python ui.input("Locked", on_input, disabled=True, width=220) ``` ```python ui.input("Copy me, not edit me", on_input, readonly=True, width=220) ``` ```python ui.input("ada@", on_input, invalid=True, width=220) ``` ```python ui.input("pyzed", on_input, on_clear=on_clear, width=220) ``` ```python ui.input("12345678", on_input, max_length=8, width=220) ``` ```python ui.input("centered", on_input, align="center", width=220) ``` ##### Base widget The `pz.*` widget underneath: no theme, every color and size is yours. ```python pz.text_input("", placeholder="pz.text_input", on_input=on_input, width=260, padding=8, radius=8, border_color="#c678dd", focus_border_color="#e5c07b") ``` #### Events Input has **3 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_input` | `ui.input`, `pz.text_input` | `(text)` | Callable that receives the new text on every keystroke. | | `on_submit` | `ui.input`, `pz.text_input` | `()` | Message or callable sent when Enter is pressed. | | `on_clear` | `ui.input` | `()` | Shows an ✕ while there is text; sent when it is clicked. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class SignUp(pz.App): def __init__(self): self.email = "" self.sent = False def set_email(self, text): # on_input: the new text on every keystroke self.email, self.sent = text, False def send(self): # on_submit: Enter self.sent = "@" in self.email def view(self): return pz.column([ ui.input(self.email, self.set_email, placeholder="Email", icon="mail", id="email", on_submit=self.send, on_clear=lambda: self.set_email(""), invalid=bool(self.email) and "@" not in self.email), ui.label("Thanks!" if self.sent else "Press Enter to send"), ], spacing=8, width=320) def on_start(self): return pz.Command.focus("email") ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Typed: text: str class SignUp(pz.App): email = "" sent = False def update(self, message): match message: case Typed(text): self.email, self.sent = text, False case "send": self.sent = "@" in self.email case "clear": self.email = "" def view(self): return ui.input(self.email, Typed, placeholder="Email", icon="mail", on_submit="send", on_clear="clear") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: email: str = "" sent: bool = False def view(state, set_state): valid = "@" in state.email return pz.column([ ui.input(state.email, lambda text: set_state(email=text, sent=False), placeholder="Email", on_submit=lambda: set_state(sent=valid), invalid=bool(state.email) and not valid), ui.label("Thanks!" if state.sent else "Press Enter to send"), ], spacing=8, width=320) ``` #### Properties and API ##### `ui.input` ```python input( value, on_input=None, *, placeholder='', icon=None, on_submit=None, on_clear=None, id=None, size='md', secure=False, width='fill', borderless=False, mono=False, disabled=False, readonly=False, invalid=False, max_length=None, align='start', theme=None, ) ``` A text field. Focus, blur and keys come from the common events: `.on(focus=..., blur=..., key_down=...)`. | Property | Default | Description | | --- | --- | --- | | `value` | *required* | Current text. | | `placeholder` | `""` | Hint text shown when empty. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `size` | `"md"` | `"sm"`, `"md"` or `"lg"`. | | `secure` | `False` | Hides the text. | | `width` | `"fill"` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `borderless` | `False` | No border or background (as in the command palette). | | `mono` | `False` | Uses the monospace font (IBM Plex Mono). | | `disabled` | `False` | Greys it out and ignores typing. | | `readonly` | `False` | Selectable and copyable, but it can't be changed. | | `invalid` | `False` | Paints the border in the error color. | | `max_length` | `None` | Ignores edits longer than this. | | `align` | `"start"` | Text alignment: `"start"`, `"center"` or `"end"`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_input`, `on_submit`, `on_clear` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#input) ##### `pz.text_input` ```python text_input( value, *, placeholder='', on_input=None, on_submit=None, id=None, size=None, font=None, padding=None, width=None, secure=False, icon=None, icon_size=None, bg=None, border_color=None, hover_border_color=None, focus_border_color=None, border_width=None, radius=None, color=None, placeholder_color=None, selection_color=None, icon_color=None, align_x=None, ) ``` A controlled text field: it shows `value` and notifies you of changes through `on_input`. For the themed field use `ui.input`. | Property | Default | Description | | --- | --- | --- | | `value` | *required* | Current text. | | `placeholder` | `""` | Hint text shown when empty. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `size` | `None` | Font size. | | `font` | `None` | Font family. | | `padding` | `None` | Inner padding: `8`, `(vertical, horizontal)` or `(top, right, bottom, left)`. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `secure` | `False` | Hides the text (passwords). | | `icon` | `None` | Icon character (use `pyzed.icons.glyph(name)`). | | `icon_size` | `None` | Icon size. | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `border_color` | `None` | Border color. | | `hover_border_color` | `None` | Border color on hover. | | `focus_border_color` | `None` | Border color when focused. | | `border_width` | `None` | Border width in pixels. | | `radius` | `None` | Corner radius: a number or `(top_left, top_right, bottom_right, bottom_left)`. | | `color` | `None` | Text or icon color. | | `placeholder_color` | `None` | Placeholder color. | | `selection_color` | `None` | Selection color. | | `icon_color` | `None` | Icon color. | | `align_x` | `None` | Horizontal alignment: `"start"`/`"left"`, `"center"`, `"end"`/`"right"`. | Events: `on_input`, `on_submit` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#text_input) #### Related - [Search input](https://albakore.github.io/pyzed/library/search-input/): An input with a magnifying glass, for filtering. - [Field](https://albakore.github.io/pyzed/library/field/): A settings row: title and description left, control right. - [Number field](https://albakore.github.io/pyzed/library/number-field/): A number with −/+ buttons, limits, step and suffix. ### Kbd > Keyboard shortcuts drawn as keys, with symbols on macOS. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/kbd/ :::tip[In plain words] Draws keyboard keys, so people learn the shortcut: Ctrl + S. ::: Draws a shortcut written as a string (`"ctrl-shift-p"`, chords like `"cmd-k cmd-s"`) as key caps. On macOS it uses symbols (⌘⇧P) and words elsewhere; `pyzed.ui.base.KEY_STYLE` forces `"symbols"` or `"words"`. `ui.format_keys` returns the labels if you draw them yourself. `ui.kbd` · Category: [Display](https://albakore.github.io/pyzed/library/#display) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#kbd) **Code:** ```python pz.column([ ui.kbd("ctrl-shift-p"), ui.kbd("ctrl-k ctrl-s"), pz.row([ui.kbd("escape", size="xs"), ui.kbd("enter", size="xs"), ui.kbd("tab", size="xs")], spacing=8), ], spacing=12, align="center") ``` #### When to use - In menus, tooltips, palettes and help screens, to teach shortcuts. - Most components already accept `keys=` and draw it for you (button, menu item, tooltip). #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ ui.kbd("ctrl-shift-p"), ui.kbd("ctrl-k ctrl-s"), pz.row([ui.kbd("escape", size="xs"), ui.kbd("enter", size="xs"), ui.kbd("tab", size="xs")], spacing=8), ], spacing=12, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Keys Write shortcuts as `"ctrl-s"`; on macOS `ctrl` becomes ⌃ and `cmd` ⌘ automatically. ```python ui.kbd("enter") ``` ```python ui.kbd("ctrl-shift-p") ``` ```python ui.kbd("ctrl-k ctrl-s") ``` ```python pz.row([ui.kbd("escape"), ui.kbd("tab"), ui.kbd("backspace"), ui.kbd("up")], spacing=6) ``` ##### Size ```python ui.kbd("ctrl-p", size="xs") ``` ```python ui.kbd("ctrl-p", size="sm") ``` #### Events Kbd has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.kbd` ```python kbd(keys, *, size='sm', theme=None) ``` Draws a shortcut as keys: `"ctrl-shift-p"`, `"cmd-k cmd-s"`. Uses symbols on macOS (⌘⇧P) and words elsewhere. | Property | Default | Description | | --- | --- | --- | | `keys` | *required* | The shortcut. | | `size` | `"sm"` | `"xs"` or `"sm"`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#kbd) ##### `ui.format_keys` ```python format_keys(keys) ``` Splits a shortcut into labels per chord: `format_keys("ctrl-shift-p") == [["Ctrl", "Shift", "P"]]`. The style is controlled by `pyzed.ui.base.KEY_STYLE` (`"auto"`, `"symbols"` or `"words"`). | Property | Default | Description | | --- | --- | --- | | `keys` | *required* | The shortcut. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#format_keys) ##### `ui.keys_text` ```python keys_text(keys) ``` A shortcut as plain text for a label or a status line: `keys_text("ctrl-shift-p") == "Ctrl+Shift+P"` (`"⌃⇧P"` with macOS symbols), chords separated by a space. Tooltips, buttons and menus take `keys=` instead and draw key caps, so never write the keys into their text. | Property | Default | Description | | --- | --- | --- | | `keys` | *required* | The shortcut. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#keys_text) #### Related - [Keybinding hint](https://albakore.github.io/pyzed/library/keybinding-hint/): A muted “Open file Ctrl P” hint. - [Shortcuts](https://albakore.github.io/pyzed/library/shortcuts/): A searchable list of key bindings, grouped. - [Tooltip](https://albakore.github.io/pyzed/library/tooltip/): A hint shown on hover, optionally with its shortcut. ### Keybinding hint > A muted “Open file Ctrl P” hint. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/keybinding-hint/ :::tip[In plain words] A quiet line that teaches a shortcut: “Open file Ctrl P”. ::: A muted hint that pairs an action with its shortcut, for footers and empty states. `ui.keybinding_hint` · Category: [Feedback](https://albakore.github.io/pyzed/library/#feedback) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#keybinding_hint) **Code:** ```python pz.column([ ui.keybinding_hint("Open file", "ctrl-p"), ui.keybinding_hint("Command palette", "ctrl-shift-p"), ui.keybinding_hint("Toggle terminal", "ctrl-j"), ], spacing=10, align="center") ``` #### When to use - In empty editors and footers, to teach the shortcuts of the most useful actions. #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ ui.keybinding_hint("Open file", "ctrl-p"), ui.keybinding_hint("Command palette", "ctrl-shift-p"), ui.keybinding_hint("Toggle terminal", "ctrl-j"), ], spacing=10, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Examples ```python ui.keybinding_hint("Search", "/") ``` ```python ui.keybinding_hint("Command palette", "ctrl-shift-p") ``` ```python ui.keybinding_hint("Keyboard shortcuts", "ctrl-k ctrl-s") ``` #### Events Keybinding hint has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.keybinding_hint` ```python keybinding_hint(text, keys, *, theme=None) ``` A muted hint like “Open file Ctrl P” for footers and empty states. | Property | Default | Description | | --- | --- | --- | | `text` | *required* | Text. | | `keys` | *required* | Shortcut shown at the end, written as a string: `"ctrl-s"`, `"cmd-k cmd-s"`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#keybinding_hint) #### Related - [Kbd](https://albakore.github.io/pyzed/library/kbd/): Keyboard shortcuts drawn as keys, with symbols on macOS. - [Empty state](https://albakore.github.io/pyzed/library/empty-state/): A centered placeholder for empty lists and searches. - [Shortcuts](https://albakore.github.io/pyzed/library/shortcuts/): A searchable list of key bindings, grouped. ### Label > Text with a theme color, size and weight; `muted` for secondary text. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/label/ :::tip[In plain words] Plain text on the screen, in the colors of the current theme. ::: Text that takes its color from the theme. `color` is a theme token (`"text"`, `"accent"`, `"error"`…) or a hex color, and `size` is a named step (`"xs"` to `"2xl"`) or a number. `ui.muted(...)` is a label with the `"text_muted"` color, for secondary text. `ui.label` · Category: [Display](https://albakore.github.io/pyzed/library/#display) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#label) **Code:** ```python pz.column([ ui.label("Pyzed draws native UIs with Iced."), ui.muted("Secondary text uses the muted color."), ui.label("Accent and semibold", color="accent", weight="semibold"), ui.label("def mono(): ...", mono=True, size="sm"), ], spacing=8) ``` #### When to use - For any text in a themed UI: it follows theme changes, unlike a hard-coded `pz.text`. - Use `ui.muted` for descriptions, hints and metadata. - For titles use [Heading](https://albakore.github.io/pyzed/library/heading/). #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ ui.label("Pyzed draws native UIs with Iced."), ui.muted("Secondary text uses the muted color."), ui.label("Accent and semibold", color="accent", weight="semibold"), ui.label("def mono(): ...", mono=True, size="sm"), ], spacing=8) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Size Named sizes follow the theme's font size; a number is a size in pixels. ```python ui.label("Extra small", size="xs") ``` ```python ui.label("Small", size="sm") ``` ```python ui.label("Medium", size="md") ``` ```python ui.label("Large", size="lg") ``` ```python ui.label("Extra large", size="xl") ``` ```python ui.label("Huge", size="2xl") ``` ##### Color ```python ui.label("Text") ``` ```python ui.muted("Muted text") ``` ```python ui.label("Accent", color="accent") ``` ```python ui.label("Success", color="success") ``` ```python ui.label("Warning", color="warning") ``` ```python ui.label("Error", color="error") ``` ```python ui.label("Any hex color", color="#c678dd") ``` ##### Weight and style ```python ui.label("Normal", weight="normal", size="lg") ``` ```python ui.label("Medium", weight="medium", size="lg") ``` ```python ui.label("Semibold", weight="semibold", size="lg") ``` ```python ui.label("Bold", weight="bold", size="lg") ``` ```python ui.label("Italic", italic=True, size="lg") ``` ```python ui.label("def mono(): ...", mono=True) ``` #### Events Label has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.label` ```python label( content, *, color='text', size='md', weight=None, mono=False, italic=False, wrap=True, theme=None, **kwargs, ) ``` Text with a theme color. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `color` | `"text"` | Theme token or hex color. Defaults to `"text"`. | | `size` | `"md"` | `"xs"` (11), `"sm"` (12), `"md"` (13.5), `"lg"` (16), `"xl"` (20), `"2xl"` (26) or a number. | | `weight` | `None` | Weight: `"medium"`, `"semibold"`, `"bold"`… | | `mono` | `False` | Uses the monospace font (IBM Plex Mono). | | `italic` | `False` | Italic. | | `wrap` | `True` | Line wrapping. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | | `**kwargs` | — | Passed to `pyzed.text`. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#label) ##### `ui.muted` ```python muted(content, **kwargs) ``` A `label` with the `"text_muted"` color. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `**kwargs` | — | Same as `label`. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#muted) #### Related - [Heading](https://albakore.github.io/pyzed/library/heading/): Semibold titles in three levels. - [Kbd](https://albakore.github.io/pyzed/library/kbd/): Keyboard shortcuts drawn as keys, with symbols on macOS. - [Badge](https://albakore.github.io/pyzed/library/badge/): A small pill for statuses, versions and counters. ### Layer > Draws an overlay over your view; clicking outside dismisses it. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/layer/ :::tip[In plain words] Puts something on top of the screen, like a search box, and closes it if you click outside. ::: Stacks `overlay` on top of `base`. Clicking outside the overlay sends `on_dismiss`, and `backdrop` dims the view behind it. With `overlay=None` it returns `base` unchanged, so it can always wrap your view. `align_x`, `align_y` and `offset` place the overlay (by default centered at the top, like a command palette). `ui.layer` · Category: [Overlays](https://albakore.github.io/pyzed/library/#overlays) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#layer) **Code:** ```python ui.layer( main_view(), ui.picker("", on_query, [(ui.PaletteItem("notes.py", on_open, icon="file-code"), []), (ui.PaletteItem("README.md", on_open, icon="file-text"), [])], placeholder="Search files…", width=420), on_dismiss=on_close, backdrop="#00000055", offset=40, ) ``` #### When to use - To show palettes, pickers, modals and menus above everything else. - For dialogs, [Dialog layer](https://albakore.github.io/pyzed/library/dialog-layer/) already centers them over a dimmed backdrop. #### Usage ```python import pyzed as pz from pyzed import ui class App(pz.App): def __init__(self): self.finder_open = False def view(self): overlay = self.finder() if self.finder_open else None return ui.layer(self.main_view(), overlay, on_dismiss=lambda: setattr(self, "finder_open", False)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Placement ```python ui.layer(main_view(), ui.card(ui.label("Overlay"), width=200), on_dismiss=on_close) ``` ```python ui.layer(main_view(), ui.card(ui.label("Overlay"), width=200), align_y="center", on_dismiss=on_close) ``` ```python ui.layer(main_view(), ui.card(ui.label("Overlay"), width=200), align_x="end", align_y="end", offset=16, on_dismiss=on_close) ``` ##### Backdrop With `overlay=None` the layer returns your view unchanged. ```python ui.layer(main_view(), ui.card(ui.label("Overlay"), width=200), backdrop="#00000088", align_y="center", on_dismiss=on_close) ``` ```python ui.layer(main_view(), None) ``` #### Events Layer has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_dismiss` | `()` | Message or callable sent on close. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class App(pz.App): def __init__(self): self.finder_open = True def view(self): finder = ui.card(ui.muted("Search files…"), width=320) return ui.layer(main_view(), finder if self.finder_open else None, on_dismiss=lambda: setattr(self, "finder_open", False)) # click outside ``` **Declarative:** ```python class App(pz.App): finder_open = True def update(self, message): match message: case "open finder": self.finder_open = True case "close finder": self.finder_open = False def view(self): overlay = ui.card(ui.muted("Search files…"), width=320) if self.finder_open else None return ui.layer(main_view(), overlay, on_dismiss="close finder") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: finder_open: bool = True def view(state, set_state): overlay = ui.card(ui.muted("Search files…"), width=320) if state.finder_open else None return ui.layer(main_view(), overlay, on_dismiss=lambda: set_state(finder_open=False)) ``` #### Properties and API ##### `ui.layer` ```python layer( base, overlay=None, *, on_dismiss=None, backdrop=None, align_x='center', align_y='start', offset=72, ) ``` Stacks `overlay` on top of `base`. Clicking outside sends `on_dismiss`. With `overlay=None` it returns `base` unchanged. | Property | Default | Description | | --- | --- | --- | | `base` | *required* | The UI underneath. | | `overlay` | `None` | What floats on top (modal, palette, menu). | | `backdrop` | `None` | Color of the backdrop that dims the UI. | | `align_x` | `"center"` | Horizontal alignment: `"start"`/`"left"`, `"center"`, `"end"`/`"right"`. | | `align_y` | `"start"` | Vertical alignment: `"start"`/`"top"`, `"center"`, `"end"`/`"bottom"`. | | `offset` | `72` | Distance from the top when `align_y` is `"start"`. | Events: `on_dismiss` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#layer) #### Related - [Modal](https://albakore.github.io/pyzed/library/modal/): A dialog surface with title, content and footer buttons. - [Popover](https://albakore.github.io/pyzed/library/popover/): Floating content at a point: context menus, color pickers. - [Dialog layer](https://albakore.github.io/pyzed/library/dialog-layer/): Centers a dialog over your view with a dimmed backdrop. ### List header > A small section title for lists, with an end slot. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/list-header/ :::tip[In plain words] A small title above a group of rows. ::: A muted section header for lists, with an optional widget at the end (usually an icon button). `ui.list_header` · Category: [Lists and menus](https://albakore.github.io/pyzed/library/#lists-and-menus) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#list_header) **Code:** ```python pz.column([ ui.list_header("RECENT", end=ui.icon_button("plus", on_new, size="xs")), ui.list_item("main.py", on_open, icon="file-code", inset=True), ui.list_item("app.py", on_open, icon="file-code", inset=True), ui.list_header("PINNED"), ui.list_item("README.md", on_open, icon="file-text", inset=True), ], width=300) ``` #### When to use - To split a list into groups (RECENT, PINNED) or to add an action to a list. #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ ui.list_header("RECENT", end=ui.icon_button("plus", on_new, size="xs")), ui.list_item("main.py", on_open, icon="file-code", inset=True), ui.list_item("app.py", on_open, icon="file-code", inset=True), ui.list_header("PINNED"), ui.list_item("README.md", on_open, icon="file-text", inset=True), ], width=300) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python pz.container(ui.list_header("RECENT"), width=240) ``` ```python pz.container(ui.list_header("PINNED", end=ui.icon_button("plus", on_new, size="xs")), width=240) ``` ```python pz.container(ui.list_header("CHANGES", end=ui.count_badge(4)), width=240) ``` #### Events List header has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.list_header` ```python list_header(title, *, end=None, theme=None) ``` A section header for lists. | Property | Default | Description | | --- | --- | --- | | `title` | *required* | Title. | | `end` | `None` | Widgets at the end (right). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#list_header) #### Related - [List item](https://albakore.github.io/pyzed/library/list-item/): A list row with icon, text and an end slot. - [Panel header](https://albakore.github.io/pyzed/library/panel-header/): Icon, title and actions on top of a dock. ### List item > A list row with icon, text and an end slot. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/list-item/ :::tip[In plain words] One row of a list: an icon, a name and maybe something on the right. ::: A list row: an icon, the text and `start`/`end` slots for any widget. It supports `selected`, `focused` (focus border), `disabled`, nesting with `indent`, and `on_right_press` for a context menu. `ui.list_item` · Category: [Lists and menus](https://albakore.github.io/pyzed/library/#lists-and-menus) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#list_item) **Code:** ```python pz.column([ ui.list_item("main.py", on_open, icon="file-code", icon_color="#3572a5", selected=True, inset=True), ui.list_item("README.md", on_open, icon="file-text", inset=True, end=ui.badge("M", tint="warning")), ui.list_item("Cargo.toml", on_open, icon="file-cog", inset=True, end=ui.kbd("ctrl-1", size="xs")), ui.list_item("old.txt", on_open, icon="file", inset=True, disabled=True), ], width=320) ``` #### When to use - For any vertical list: recent files, search results, settings categories, people. - Use `inset=True` inside panels so the highlight has a margin. #### Usage ```python import pyzed as pz from pyzed import ui class Recent(pz.App): def __init__(self): self.files = ["main.py", "app.py", "README.md"] self.current = "main.py" def view(self): return pz.column([ ui.list_item(f, lambda f=f: setattr(self, "current", f), icon="file", selected=f == self.current, inset=True) for f in self.files ]) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python pz.container(ui.list_item("README.md", on_open), width=240) ``` ```python pz.container(ui.list_item("README.md", on_open, icon="file-text"), width=240) ``` ```python pz.container(ui.list_item("main.py", on_open, icon="file-code", icon_color="#3572a5"), width=240) ``` ```python pz.container(ui.list_item("app.py", on_open, icon="file-code", end=ui.badge("M", tint="warning")), width=240) ``` ```python pz.container(ui.list_item("Buy milk", on_open, start=ui.checkbox(True, on_toggle)), width=240) ``` ```python pz.container(ui.list_item("Delete project", on_open, icon="trash-2", color="error"), width=240) ``` ##### State ```python pz.container(ui.list_item("main.py", on_open, icon="file-code", selected=True), width=240) ``` ```python pz.container(ui.list_item("main.py", on_open, icon="file-code", focused=True), width=240) ``` ```python pz.container(ui.list_item("old.txt", on_open, icon="file", disabled=True), width=240) ``` ```python pz.container(ui.list_item("main.py", on_open, icon="file-code", selected=True, inset=True), width=240) ``` ```python pz.container(ui.list_item("button.rs", on_open, icon="file-code", indent=24), width=240) ``` ##### States and events `on_right_press` opens a context menu and `tooltip=` shows on hover. ```python pz.container(ui.list_item("main.py", on_press, icon="file", description="src/app"), width=300) ``` ```python pz.container(ui.list_item("Rename me", on_press, icon="pencil", on_double_press=on_rename), width=300) ``` #### Events List item has **3 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `()` | Message or callable sent on press. `None` disables the control. | | `on_right_press` | `()` | Right click. | | `on_double_press` | `()` | Sent on a double click (open, rename…). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Recent(pz.App): def __init__(self): self.files = ["main.py", "app.py", "README.md"] self.current = "main.py" self.opened = None def view(self): return pz.column([ ui.list_item(f, lambda f=f: setattr(self, "current", f), icon="file", # on_press selected=f == self.current, inset=True, on_double_press=lambda f=f: setattr(self, "opened", f), on_right_press=lambda f=f: print("menu for", f)) for f in self.files ], width=280) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Select: path: str @dataclass class Open: path: str class Recent(pz.App): files = ["main.py", "app.py", "README.md"] current, opened = "main.py", None def update(self, message): match message: case Select(path): self.current = path case Open(path): self.opened = path def view(self): return pz.column([ui.list_item(f, Select(f), icon="file", selected=f == self.current, on_double_press=Open(f)) for f in self.files], width=280) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: files: tuple = ("main.py", "app.py", "README.md") current: str = "main.py" def file_row(name, selected, select): return ui.list_item(name, select, icon="file", selected=selected, inset=True) def view(state, set_state): return pz.column([file_row(f, f == state.current, lambda f=f: set_state(current=f)) for f in state.files], width=280) ``` #### Properties and API ##### `ui.list_item` ```python list_item( content, on_press=None, *, icon=None, icon_color=None, start=None, end=None, selected=False, focused=False, indent=0, height=26, color=None, inset=False, disabled=False, on_right_press=None, on_double_press=None, description=None, tooltip=None, theme=None, ) ``` A list row: icon, text and a slot at the end. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Text or widget. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `icon_color` | `None` | Icon color: a theme token or a hex color. | | `start` | `None` | Widgets at the start (left). | | `end` | `None` | Widgets at the end (right). | | `selected` | `False` | Marks it as selected. | | `focused` | `False` | Draws a focus border. | | `indent` | `0` | Left indentation, in pixels. | | `height` | `26` | Row height. | | `color` | `None` | Text color. | | `inset` | `False` | With margin and rounded corners (menus, palettes). | | `disabled` | `False` | Disables it (ignores clicks). | | `description` | `None` | A muted second line (the row grows to 40 px unless `height` is set). | | `tooltip` | `None` | Text shown on hover. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_press`, `on_right_press`, `on_double_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#list_item) #### Related - [List header](https://albakore.github.io/pyzed/library/list-header/): A small section title for lists, with an end slot. - [Tree](https://albakore.github.io/pyzed/library/tree/): A collapsible file tree with icons and git colors. - [Menu](https://albakore.github.io/pyzed/library/menu/): A context menu with icons, shortcuts and checks. ### Markdown > Renders Markdown with the theme's colors. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/markdown/ :::tip[In plain words] Shows formatted text (titles, lists, links) written in the simple Markdown format. ::: Renders Markdown (headings, lists, code blocks, quotes, tables, links) with the theme's text, link and code colors. `on_link(url)` receives clicked links. `pz.markdown` is the base widget with explicit colors. `ui.markdown` · Category: [Code and tools](https://albakore.github.io/pyzed/library/#code-and-tools) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#markdown) **Code:** ```python ui.markdown('''## Release notes Pyzed **0.4** adds the *component designer*, `pyzed build` and [styles](https://iced.rs). - Track grids and flex - Ready-made dialogs ''', width=460, on_link=on_link) ``` #### When to use - For READMEs, release notes, help pages and chat messages. #### Usage ```python from pyzed import ui ui.markdown('''## Release notes Pyzed **0.4** adds the *component designer*, `pyzed build` and [styles](https://iced.rs). - Track grids and flex - Ready-made dialogs ''', width=460, on_link=on_link) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Elements ```python ui.markdown("## Title\nSome **bold** and *italic* text.", width=320) ``` ```python ui.markdown("- Fast\n- Native\n- Pythonic\n\n1. Install\n2. Run", width=320) ``` ```python ui.markdown("Run `pyzed new`:\n\n```python\nimport pyzed as pz\n```", width=320) ``` ```python ui.markdown("> Desktop UIs in Python.\n\nSee [the docs](https://albakore.github.io/pyzed/).", width=320, on_link=on_link) ``` ```python ui.markdown("| Key | Action |\n| --- | --- |\n| ctrl-s | Save |\n| ctrl-p | Open |", width=320) ``` #### Events Markdown has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_link` | `ui.markdown`, `pz.markdown` | `(url)` | Callable that receives the URL when a link is clicked. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python import webbrowser class Notes(pz.App): def __init__(self): self.last = None def follow(self, url): # on_link: the URL of the clicked link self.last = url webbrowser.open(url) def view(self): return ui.markdown("Read the [docs](https://albakore.github.io/pyzed/) or the " "[changelog](https://github.com/albakore/pyzed).", on_link=self.follow) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Link: url: str class Notes(pz.App): def update(self, message): match message: case Link(url) if url.startswith("app:"): print("internal page", url[4:]) # links can drive the app, too case Link(url): print("open", url) def view(self): return ui.markdown("Go to [settings](app:settings) or the [docs](https://albakore.github.io/pyzed/).", on_link=Link) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: page: str = "home" PAGES = {"home": "Welcome. See [about](about).", "about": "Made with Pyzed. Back [home](home)."} def view(state, set_state): text = PAGES.get(state.page, "Not found. Back [home](home).") return ui.markdown(text, on_link=lambda url: set_state(page=url)) ``` #### Properties and API ##### `ui.markdown` ```python markdown(source, *, size=None, on_link=None, width=None, selectable=None, theme=None) ``` `pz.markdown` with the theme's text, link and code colors. | Property | Default | Description | | --- | --- | --- | | `source` | *required* | The Markdown text. | | `size` | `None` | Size. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `selectable` | `None` | Same as in `pz.markdown`; the selection uses the theme's `selection` color. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_link` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#markdown) ##### `pz.markdown` ```python markdown( source, *, size=14.0, color=None, link_color=None, code_color=None, code_bg=None, on_link=None, width=None, selectable=None, selection_color=None, ) ``` Renders Markdown (headings, lists, code blocks, quotes, tables, links…). For the theme colors use `ui.markdown`. | Property | Default | Description | | --- | --- | --- | | `source` | *required* | The Markdown text. | | `size` | `14.0` | Size. | | `color` | `None` | Text or icon color. | | `link_color` | `None` | Link color. | | `code_color` | `None` | Code color. | | `code_bg` | `None` | Code background. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `selectable` | `None` | `True` lets the mouse select the text (drag, double-click a word, triple-click a block) and Ctrl+C copy it. A string names a selection group: the texts and Markdown of one group form a single selection, in the order they are drawn (the lines of a log, the messages of a chat). | | `selection_color` | `None` | Color behind the selected text. | Events: `on_link` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#markdown) #### Related - [Rich text](https://albakore.github.io/pyzed/library/rich-text/): One block of text mixing colors, weights and links. - [Text](https://albakore.github.io/pyzed/library/text/): A piece of text with size, color, font and weight. ### Menu > A context menu with icons, shortcuts and checks. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/menu/ :::tip[In plain words] The list of options that appears when you right-click or press a “more” button. ::: A floating context menu. Items are `ui.MenuItem(label, on_press, icon=, keys=, checked=, danger=, disabled=)`; `ui.SEPARATOR` draws a line between groups and a plain string is a header. Show it with a [Popover](https://albakore.github.io/pyzed/library/popover/) or a [Layer](https://albakore.github.io/pyzed/library/layer/). `ui.menu` · Category: [Lists and menus](https://albakore.github.io/pyzed/library/#lists-and-menus) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#menu) **Code:** ```python ui.menu([ ui.MenuItem("New file", on_new, icon="file-plus", keys="ctrl-n"), ui.MenuItem("New folder", on_new_folder, icon="folder-plus"), ui.SEPARATOR, "EDIT", ui.MenuItem("Copy path", on_copy, keys="ctrl-alt-c"), ui.MenuItem("Soft wrap", on_wrap, checked=True), ui.SEPARATOR, ui.MenuItem("Delete", on_delete, icon="trash-2", danger=True), ]) ``` #### When to use - For right-click menus and the options of a split button or an ellipsis button. - Mark destructive actions with `danger=True` and put them last. #### Usage ```python from pyzed import ui ui.menu([ ui.MenuItem("New file", on_new, icon="file-plus", keys="ctrl-n"), ui.MenuItem("New folder", on_new_folder, icon="folder-plus"), ui.SEPARATOR, "EDIT", ui.MenuItem("Copy path", on_copy, keys="ctrl-alt-c"), ui.MenuItem("Soft wrap", on_wrap, checked=True), ui.SEPARATOR, ui.MenuItem("Delete", on_delete, icon="trash-2", danger=True), ]) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Items ```python ui.menu([ui.MenuItem("Open", on_open), ui.MenuItem("Rename", on_rename), ui.MenuItem("Duplicate", on_duplicate)], width=200) ``` ```python ui.menu([ui.MenuItem("Copy", on_copy, icon="copy", keys="ctrl-c"), ui.MenuItem("Paste", on_paste, icon="clipboard", keys="ctrl-v")], width=220) ``` ```python ui.menu([ui.MenuItem("Soft wrap", on_wrap, checked=True), ui.MenuItem("Minimap", on_minimap, checked=False)], width=200) ``` ```python ui.menu([ui.MenuItem("Rename", on_rename), ui.SEPARATOR, ui.MenuItem("Delete", on_delete, icon="trash-2", danger=True)], width=200) ``` ```python ui.menu([ui.MenuItem("Undo", on_undo, keys="ctrl-z"), ui.MenuItem("Redo", on_redo, keys="ctrl-shift-z", disabled=True)], width=220) ``` ##### Groups ```python ui.menu(["FILE", ui.MenuItem("New", on_new, keys="ctrl-n"), ui.SEPARATOR, "EDIT", ui.MenuItem("Find", on_find, keys="ctrl-f")], width=220) ``` ##### States and events ```python ui.menu([ui.MenuItem("Share", on_press, icon="share", submenu=True), ui.MenuItem("Rename", on_press, description="F2 also works")]) ``` ```python ui.menu([ui.MenuItem(f"Recent {i}", on_press) for i in range(10)], max_height=140) ``` #### Events Menu has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `()` | Message or callable sent on press. `None` disables the control. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Files(pz.App): def __init__(self): self.wrap = True self.log = [] def view(self): return ui.menu([ ui.MenuItem("New file", lambda: self.log.append("new"), icon="file-plus", keys="ctrl-n"), ui.MenuItem("Soft wrap", lambda: setattr(self, "wrap", not self.wrap), checked=self.wrap), ui.SEPARATOR, ui.MenuItem("Delete", lambda: self.log.append("delete"), icon="trash-2", danger=True), ]) ``` **Declarative:** ```python class Files(pz.App): wrap = True def update(self, message): # each item's on_press is a message match message: case "new": print("new file") case "wrap": self.wrap = not self.wrap def view(self): return ui.menu([ui.MenuItem("New file", "new", icon="file-plus", keys="ctrl-n"), ui.MenuItem("Soft wrap", "wrap", checked=self.wrap)]) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: wrap: bool = True def view(state, set_state): return ui.menu([ ui.MenuItem("Soft wrap", lambda: set_state(wrap=not state.wrap), checked=state.wrap), ui.MenuItem("Delete", None, icon="trash-2", danger=True, disabled=True), ]) ``` #### Properties and API ##### `ui.menu` ```python menu(items, *, width=240, max_height=None, theme=None) ``` A floating context menu. Use `ui.SEPARATOR` between groups; a plain string is a header. | Property | Default | Description | | --- | --- | --- | | `items` | *required* | List of `MenuItem`, `ui.SEPARATOR` or strings. | | `width` | `240` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `max_height` | `None` | Scrolls a menu taller than this. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#menu) ##### `ui.MenuItem` ```python @dataclass class MenuItem(label, on_press=None, icon=None, keys=None, disabled=False, danger=False, checked=None, description=None, submenu=False) ``` An entry of `ui.menu`. | Property | Default | Description | | --- | --- | --- | | `label` | *required* | Label text. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `keys` | `None` | Shortcut shown at the end, written as a string: `"ctrl-s"`, `"cmd-k cmd-s"`. | | `disabled` | `False` | Disables it (ignores clicks). | | `danger` | `False` | In red (destructive actions). | | `checked` | `None` | Shows a check mark (`True`/`False`) or nothing (`None`). | | `description` | `None` | A muted second line. | | `submenu` | `False` | Ends the row with a chevron; open the next menu beside it in `on_press`. | Events: `on_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#menuitem) ##### `ui.SEPARATOR` Separator for `ui.menu`. [Full reference →](https://albakore.github.io/pyzed/reference/ui/#separator) #### Related - [Popover](https://albakore.github.io/pyzed/library/popover/): Floating content at a point: context menus, color pickers. - [Split button](https://albakore.github.io/pyzed/library/split-button/): A main action plus an arrow that opens more options. - [List item](https://albakore.github.io/pyzed/library/list-item/): A list row with icon, text and an end slot. ### Modal > A dialog surface with title, content and footer buttons. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/modal/ :::tip[In plain words] A window inside the window that asks for your attention before you go on. ::: A dialog surface with a title, a close button, your content and a footer of buttons. Use it as the overlay of `ui.layer` or `ui.dialog_layer`. The ready-made [dialogs](https://albakore.github.io/pyzed/library/confirm/) are built on it. `ui.modal` · Category: [Overlays](https://albakore.github.io/pyzed/library/#overlays) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#modal) **Code:** ```python ui.modal( ui.muted("notes.py has unsaved changes. Save them before closing?"), title="Save changes?", on_close=on_close, footer=[ui.button("Don't save", on_discard, variant="ghost"), ui.button("Cancel", on_close), ui.button("Save", on_save, variant="solid")], width=440, ) ``` #### When to use - For dialogs with your own content: a form, settings, an About box. #### Usage ```python from pyzed import ui ui.modal( ui.muted("notes.py has unsaved changes. Save them before closing?"), title="Save changes?", on_close=on_close, footer=[ui.button("Don't save", on_discard, variant="ghost"), ui.button("Cancel", on_close), ui.button("Save", on_save, variant="solid")], width=440, ) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python ui.modal(ui.muted("Your trial ends in 3 days."), width=320) ``` ```python ui.modal(ui.muted("Your trial ends in 3 days."), title="Trial", on_close=on_close, width=320) ``` ```python ui.modal(ui.muted("Discard the draft?"), title="Draft", on_close=on_close, width=320, footer=[ui.button("Cancel", on_close), ui.button("Discard", on_discard, variant="error")]) ``` ##### States and events `max_height=` scrolls long content, and Escape sends `on_close` while the dialog has focus. ```python ui.modal(ui.input("notes.md", on_input), title="Rename", description="Choose a new name", icon="pencil", on_close=on_close, width="sm", footer=[ui.button("Rename", on_press, variant="solid")]) ``` #### Examples ##### Over the app Wrap the view with `ui.dialog_layer` to center it over a dimmed backdrop. **Code:** ```python ui.dialog_layer(main_view(), ui.modal( pz.column([ui.input("", on_input, placeholder="Project name"), ui.checkbox(True, on_toggle, label="Create a git repository")], spacing=10), title="New project", on_close=on_close, footer=[ui.button("Cancel", on_close), ui.button("Create", on_create, variant="solid")], width=380, ), on_dismiss=on_close) ``` #### Events Modal has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_close` | `()` | The close button; also sent by Escape while the dialog has focus. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Notes(pz.App): def __init__(self): self.asking = True def save(self): self.asking = False def view(self): dialog = ui.modal(ui.muted("Save your changes before closing?"), title="Save changes?", on_close=lambda: setattr(self, "asking", False), # ✕ and Escape footer=[ui.button("Save", self.save, variant="solid")], width=420) return ui.dialog_layer(main_view(), dialog if self.asking else None) ``` **Declarative:** ```python class Notes(pz.App): asking = True def update(self, message): if message in ("save", "close"): self.asking = False def view(self): dialog = ui.modal(ui.muted("Save your changes?"), title="Save changes?", on_close="close", footer=[ui.button("Save", "save", variant="solid")]) return ui.dialog_layer(main_view(), dialog if self.asking else None) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: asking: bool = True def view(state, set_state): close = lambda: set_state(asking=False) dialog = ui.modal(ui.muted("Save your changes?"), title="Save changes?", on_close=close, footer=[ui.button("Save", close, variant="solid")]) return ui.dialog_layer(main_view(), dialog if state.asking else None) ``` #### Properties and API ##### `ui.modal` ```python modal( content, *, title=None, on_close=None, width=480, footer=(), description=None, icon=None, max_height=None, theme=None, ) ``` A dialog. Use it as the `overlay` of `ui.layer`. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `title` | `None` | Title. | | `width` | `480` | Pixels or `"sm"` (360), `"md"` (480), `"lg"` (640) or `"xl"` (820). | | `footer` | `()` | Footer buttons, aligned to the right. | | `description` | `None` | Muted line under the title. | | `icon` | `None` | Icon before the title. | | `max_height` | `None` | Scrolls content taller than this, keeping the header and footer in view. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_close` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#modal) #### Related - [Dialog layer](https://albakore.github.io/pyzed/library/dialog-layer/): Centers a dialog over your view with a dimmed backdrop. - [Layer](https://albakore.github.io/pyzed/library/layer/): Draws an overlay over your view; clicking outside dismisses it. - [Confirm](https://albakore.github.io/pyzed/library/confirm/): A yes/no question, red for destructive actions. ### Mouse area > Makes any widget react to clicks, hover, drags and the wheel. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/mouse-area/ :::tip[In plain words] An invisible layer that lets anything (a picture, a card, a drawing) notice clicks and the mouse. ::: `pz.mouse_area` wraps any widget and reports what the mouse does over it: presses (left, right, middle, double click), entering and leaving, moving (`on_move(x, y)`) and the wheel (`on_scroll(dx, dy)`); `cursor` changes the pointer. `pz.hover(base, top)` shows `top` over `base` only while the pointer is over it, and `pz.opaque` stops clicks from reaching what is under a widget in a `stack`. `pz.mouse_area` · Category: [Actions](https://albakore.github.io/pyzed/library/#actions) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#mouse_area) **Code:** ```python pz.mouse_area( ui.card(pz.row([pz.icon("folder", size=20), ui.label("Open project…")], spacing=10, align="center"), width=280), on_press=on_open, on_right_press=on_menu, cursor="pointer", ) ``` #### When to use - To make a card, an image or a custom drawing clickable without turning it into a button. - For right-click menus (`on_right_press`), drag gestures (`on_move`) and zoom with the wheel. - `pz.hover` for actions that appear on hover, like the close button of a tab. #### Usage ```python import pyzed as pz class Board(pz.App): def __init__(self): self.pointer = (0, 0) self.zoom = 1.0 def view(self): return pz.mouse_area( self.drawing(), on_move=lambda x, y: setattr(self, "pointer", (x, y)), on_scroll=lambda dx, dy: setattr(self, "zoom", max(0.1, self.zoom + dy * 0.1)), on_double_click=self.reset, cursor="crosshair", ) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Cursor The pointer shape is only visible with a real mouse; the shot shows the wrapped widget. ```python pz.mouse_area(ui.card(ui.label("Click me"), width=180), on_press=on_open, cursor="pointer") ``` ```python pz.mouse_area(ui.card(ui.label("Drag me"), width=180), on_move=on_drag, cursor="grab") ``` ```python pz.mouse_area(pz.canvas([draw.circle(60, 40, 24, fill="#74ade8")], width=120, height=80), on_press=on_pick, cursor="crosshair") ``` ##### Hover content `pz.hover` only draws its `top` while the pointer is over it: here, the close button of a row. ```python pz.hover(ui.list_item("notes.py", on_open, icon="file-text"), pz.container(ui.icon_button("x", on_close, size="xs"), align_x="end", width="fill")) ``` ```python pz.hover(ui.list_item("notes.py", on_open, icon="file-text"), pz.container(ui.icon_button("x", on_close, size="xs"), align_x="end", width="fill")) ``` #### Events Mouse area has **10 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `()` | Left click (on press). | | `on_release` | `()` | On releasing the left button. | | `on_right_press` | `()` | Right click (context menus). | | `on_double_click` | `()` | Double click. | | `on_enter` | `()` | The mouse enters. | | `on_exit` | `()` | The mouse leaves. | | `on_move` | `(x, y)` | Called with `(x, y)` when the mouse moves. | | `on_scroll` | `(dx, dy)` | Callable that receives `(dx, dy)` in lines when the wheel is used. | | `on_middle_press` | `()` | Middle-button click. | | `on_middle_release` | `()` | Middle button released (pan gestures, for example). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Board(pz.App): def __init__(self): self.pointer, self.hovering, self.zoom = (0, 0), False, 1.0 def view(self): return pz.mouse_area( ui.card(ui.label(f"{self.pointer} · zoom {self.zoom:.1f}"), width=320), on_enter=lambda: setattr(self, "hovering", True), on_exit=lambda: setattr(self, "hovering", False), on_move=lambda x, y: setattr(self, "pointer", (round(x), round(y))), on_scroll=lambda dx, dy: setattr(self, "zoom", max(0.1, self.zoom + dy * 0.1)), on_double_click=lambda: setattr(self, "zoom", 1.0), on_right_press=lambda: print("context menu"), cursor="crosshair", ) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Moved: x: float y: float class Board(pz.App): pointer = (0, 0) def update(self, message): match message: case Moved(x, y): self.pointer = (round(x), round(y)) case "reset": self.pointer = (0, 0) def view(self): return pz.mouse_area(ui.card(ui.label(str(self.pointer)), width=320), on_move=Moved, on_double_click="reset") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: hovering: bool = False def view(state, set_state): return pz.mouse_area(ui.card(ui.label("Hovering" if state.hovering else "Point at me"), width=320), on_enter=lambda: set_state(hovering=True), on_exit=lambda: set_state(hovering=False)) ``` #### Tips :::tip Hover and pointer states only exist with a real mouse, so the previews draw them as they look; see the animated clips in [Showcase](https://albakore.github.io/pyzed/showcase/) for the real thing. ::: #### Properties and API ##### `pz.mouse_area` ```python mouse_area( content, *, on_press=None, on_release=None, on_right_press=None, on_double_click=None, on_enter=None, on_exit=None, on_move=None, on_scroll=None, on_middle_press=None, on_middle_release=None, cursor=None, ) ``` Detects mouse events over its content. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `cursor` | `None` | `"pointer"`, `"text"`, `"grab"`, `"grabbing"`, `"crosshair"`, `"not-allowed"`, `"resize-horizontal"`, `"resize-vertical"`, `"move"` or `"default"`. | Events: `on_press`, `on_release`, `on_right_press`, `on_double_click`, `on_enter`, `on_exit`, `on_move`, `on_scroll`, `on_middle_press`, `on_middle_release` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#mouse_area) ##### `pz.hover` ```python hover(base, top) ``` Shows `top` over `base` only while the mouse is over it (for example, a tab's close button). | Property | Default | Description | | --- | --- | --- | | `base` | *required* | Widget underneath. | | `top` | *required* | Widget that appears on hover. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#hover) ##### `pz.opaque` ```python opaque(content) ``` Makes a widget block the mouse for whatever is below it in a `stack`. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#opaque) #### Related - [Button](https://albakore.github.io/pyzed/library/button/): The themed button: variants, sizes, icons and shortcuts. - [Popover](https://albakore.github.io/pyzed/library/popover/): Floating content at a point: context menus, color pickers. - [Stack](https://albakore.github.io/pyzed/library/stack/): Layers children on top of each other; `pin` places one at x, y. ### Number field > A number with −/+ buttons, limits, step and suffix. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/number-field/ :::tip[In plain words] A box with a number and − / + buttons to make it smaller or bigger. ::: A numeric field with − and + buttons. You can also type a value: `on_change` receives the number already clamped to `min`/`max`, and text that is not a number is ignored. `ui.number_field` · Category: [Forms](https://albakore.github.io/pyzed/library/#forms) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#number_field) **Code:** ```python pz.row([ ui.number_field(14, on_change, min=8, max=32, suffix="px"), ui.number_field(4, on_change, min=1, max=8), ui.number_field(0.5, on_change, step=0.1, suffix="s", width=140), ], spacing=12) ``` #### When to use - For exact values with sensible limits: font size, tab width, port, retries. - Use `suffix` for units (`"px"`, `"ms"`, `"%"`). #### Usage ```python import pyzed as pz from pyzed import ui class Settings(pz.App): def __init__(self): self.font_size = 14 def view(self): return ui.number_field(self.font_size, lambda v: setattr(self, "font_size", v), min=8, max=32, suffix="px") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python ui.number_field(4, on_change, min=1, max=8) ``` ```python ui.number_field(14, on_change, min=8, max=32, suffix="px") ``` ```python ui.number_field(0.5, on_change, step=0.1, suffix="s", width=140) ``` ```python ui.number_field(8080, on_change, min=1, max=65535, align="start", width=140) ``` ##### Limits At a limit its button is dimmed and the value can't go further. ```python ui.number_field(1, on_change, min=1, max=8) ``` ```python ui.number_field(8, on_change, min=1, max=8) ``` ##### States and events Once clicked, ↑/↓ step it (Shift: ten steps) and Home/End jump to `min`/`max`. ```python ui.number_field(9.5, on_change, step=0.5, prefix="$", decimals=2, width=150) ``` ```python ui.number_field(70000, on_change, invalid=True, width=150) ``` ```python ui.number_field(4, on_change, min=1, max=8, disabled=True) ``` #### Events Number field has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_change` | `(value)` | Callable that receives the new value. | | `on_submit` | `()` | Sent on Enter. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Settings(pz.App): def __init__(self): self.font_size = 14 self.applied = 14 def view(self): return pz.row([ ui.number_field(self.font_size, lambda v: setattr(self, "font_size", v), # on_change min=8, max=32, suffix="px", on_submit=lambda: setattr(self, "applied", self.font_size)), # Enter pz.text("Preview", size=self.applied), ], spacing=12, align="center") ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class FontSize: value: float class Settings(pz.App): font_size = 14 def update(self, message): match message: case FontSize(value): self.font_size = value def view(self): return ui.number_field(self.font_size, FontSize, min=8, max=32, suffix="px") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: font_size: float = 14 def view(state, set_state): return pz.row([ui.number_field(state.font_size, lambda v: set_state(font_size=v), min=8, max=32), pz.text("Preview", size=state.font_size)], spacing=12, align="center") ``` #### Properties and API ##### `ui.number_field` ```python number_field( value, on_change=None, *, min=None, max=None, step=1, width=120, suffix=None, prefix=None, align='center', decimals=None, disabled=False, invalid=False, id=None, on_submit=None, steppers=True, drag=True, drag_step=None, theme=None, ) ``` A numeric field with −/+ buttons that you can also drag, like Figma's. `on_change(value)` receives the number already clamped to `min`/`max`; anything that can't be parsed as a number is ignored. Press and move the mouse sideways over the number to change it (it keeps going outside the window); double-click it to type a value, and Enter, Escape or a click outside to finish. Once clicked, ↑/↓ step it (Shift: ten steps) and Home/End jump to `min`/`max`. | Property | Default | Description | | --- | --- | --- | | `value` | *required* | Current value. | | `min` | `None` | Minimum. | | `max` | `None` | Maximum. | | `step` | `1` | Button step. | | `width` | `120` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `suffix` | `None` | Unit shown at the end (`"px"`, `"%"`…). | | `prefix` | `None` | Text before the number (`"$"`…). | | `align` | `"center"` | Where the number sits between the buttons: `"center"` (default), `"start"` or `"end"`. | | `decimals` | `None` | Decimals shown (by default, as many as `step`). | | `disabled` | `False` | Greys it out. | | `invalid` | `False` | Paints the border in the error color. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `steppers` | `True` | Shows the −/+ buttons (`False`: a compact field, as in a property grid). | | `drag` | `True` | Lets the mouse change it by dragging (`False`: a plain text field). | | `drag_step` | `None` | How much each pixel dragged adds (by default `step`, up to 1; steps under 1 take three pixels each). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_change`, `on_submit` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#number_field) #### Related - [Slider](https://albakore.github.io/pyzed/library/slider/): Pick a number in a range by dragging. - [Input](https://albakore.github.io/pyzed/library/input/): A controlled text field with icon, placeholder and password mode. - [Field](https://albakore.github.io/pyzed/library/field/): A settings row: title and description left, control right. ### Panel > A dockable, resizable side panel. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/panel/ :::tip[In plain words] A side area of the window, like the file list on the left, that you can make wider or narrower. ::: A dockable panel with an optional header. `side` decides which edge gets the border line; with a numeric `width` (`height` for the bottom) that edge can be dragged to resize it, and `on_resize` reports the new size. `ui.panel` · Category: [Workspace](https://albakore.github.io/pyzed/library/#workspace) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#panel) **Code:** ```python pz.row([ ui.panel( pz.column([ui.list_item("Inbox", on_open, icon="inbox", selected=True, inset=True), ui.list_item("Archive", on_open, icon="archive", inset=True)]), header=ui.panel_header("Mail", [ui.icon_button("plus", on_new, size="xs")], icon="mail"), width=220, side="left", ), pz.container(ui.muted("Content"), center=True, width="fill", height="fill"), ], height="fill") ``` #### When to use - When you build your own layout instead of `ui.workspace`: sidebars, inspectors, outlines. #### Usage ```python import pyzed as pz from pyzed import ui pz.row([ ui.panel( pz.column([ui.list_item("Inbox", on_open, icon="inbox", selected=True, inset=True), ui.list_item("Archive", on_open, icon="archive", inset=True)]), header=ui.panel_header("Mail", [ui.icon_button("plus", on_new, size="xs")], icon="mail"), width=220, side="left", ), pz.container(ui.muted("Content"), center=True, width="fill", height="fill"), ], height="fill") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Side ```python pz.row([ui.panel(ui.list_item("Inbox", icon="inbox", inset=True), header=ui.panel_header("Mail"), width=160, side="left"), pz.container(width="fill")], height="fill") ``` ```python pz.row([pz.container(width="fill"), ui.panel(ui.muted("Properties"), header=ui.panel_header("Inspector"), width=160, side="right")], height="fill") ``` ```python pz.column([pz.container(height="fill"), ui.panel(ui.terminal("$ ls"), header=ui.panel_header("Terminal"), height=100, side="bottom")], width="fill") ``` #### Events Panel has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_resize` | `(size)` | Called with the new size when a drag ends. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Mail(pz.App): def __init__(self): self.width = 220 def view(self): return pz.row([ ui.panel(ui.muted("Inbox"), header=ui.panel_header("Mail"), width=self.width, on_resize=lambda size: setattr(self, "width", size)), # when the drag ends main_view(), ], height="fill") ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Width: size: float class Mail(pz.App): width = 220 def update(self, message): match message: case Width(size): self.width = size def view(self): return pz.row([ui.panel(ui.muted("Inbox"), width=self.width, on_resize=Width), main_view()], height="fill") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: width: float = 220 def view(state, set_state): return pz.row([ui.panel(ui.muted("Inbox"), width=state.width, on_resize=lambda s: set_state(width=s)), main_view()], height="fill") ``` #### Properties and API ##### `ui.panel` ```python panel( content, *, header=None, width=None, height=None, side='left', resizable=True, on_resize=None, min_size=120, theme=None, ) ``` A dockable panel. `side` decides which edge gets the border line; with a numeric `width` (`height` for the bottom) that border can be dragged to resize it. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `header` | `None` | Header (`ui.panel_header`). | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `side` | `"left"` | `"left"`, `"right"` or `"bottom"`. | | `resizable` | `True` | `False` keeps the size fixed. | | `min_size` | `120` | Smallest size when resizing. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_resize` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#panel) #### Related - [Panel header](https://albakore.github.io/pyzed/library/panel-header/): Icon, title and actions on top of a dock. - [Workspace](https://albakore.github.io/pyzed/library/workspace/): The layout of an editor-style window: title bar, docks, center, status bar. - [Split](https://albakore.github.io/pyzed/library/split/): Two panes with a draggable divider. ### Panel header > Icon, title and actions on top of a dock. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/panel-header/ :::tip[In plain words] The title row of a side panel, with its buttons. ::: The header of a dock or panel: an optional icon, the title and action buttons on the right. `ui.panel_header` · Category: [Workspace](https://albakore.github.io/pyzed/library/#workspace) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#panel_header) **Code:** ```python pz.column([ ui.panel_header("Project", [ui.icon_button("plus", on_new, size="xs"), ui.icon_button("ellipsis", on_menu, size="xs")]), ui.panel_header("Terminal", [ui.icon_button("x", on_close, size="xs")], icon="terminal"), ], spacing=12, width=320) ``` #### When to use - At the top of every dock (Project, Outline, Terminal) to name it and hold its actions. #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ ui.panel_header("Project", [ui.icon_button("plus", on_new, size="xs"), ui.icon_button("ellipsis", on_menu, size="xs")]), ui.panel_header("Terminal", [ui.icon_button("x", on_close, size="xs")], icon="terminal"), ], spacing=12, width=320) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python pz.container(ui.panel_header("Project"), width=280) ``` ```python pz.container(ui.panel_header("Terminal", icon="terminal"), width=280) ``` ```python pz.container(ui.panel_header("Project", [ui.icon_button("plus", on_new, size="xs"), ui.icon_button("ellipsis", on_menu, size="xs")]), width=280) ``` ```python pz.container(ui.panel_header("Outline", height=40), width=280) ``` #### Events Panel header has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.panel_header` ```python panel_header(title, actions=(), *, icon=None, height=32, theme=None) ``` A panel header: icon, title and actions. | Property | Default | Description | | --- | --- | --- | | `title` | *required* | Title. | | `actions` | `()` | Extra widgets (usually buttons) shown as actions. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `height` | `32` | Height. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#panel_header) #### Related - [Panel](https://albakore.github.io/pyzed/library/panel/): A dockable, resizable side panel. - [List header](https://albakore.github.io/pyzed/library/list-header/): A small section title for lists, with an end slot. ### Picker > A searchable list on a floating surface, with fuzzy matching. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/picker/ :::tip[In plain words] A floating search box with a list of results that narrows as you type. ::: A search box over a list of results on a floating surface: the basis of the command palette and the file finder. `ui.fuzzy_filter(query, items, key=)` ranks items (best match first) and returns `[(item, positions), ...]`; pass those pairs to `picker` to highlight the matches. `ui.fuzzy_match` scores one string and `ui.highlighted` draws one with its matches. `ui.picker` · Category: [Overlays](https://albakore.github.io/pyzed/library/#overlays) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#picker) **Code:** ```python files = ["src/app.rs", "src/render.rs", "python/pyzed/app.py", "python/pyzed/theme.py", "README.md"] items = ui.fuzzy_filter("app", [ui.PaletteItem(f, on_open, icon="file-code") for f in files], key=lambda item: item.label) ui.picker("app", on_query, items, selected=0, placeholder="Search files…", width=480) ``` #### When to use - For your own finders: files, symbols, branches, projects, emoji. #### Usage ```python import pyzed as pz from pyzed import ui class Finder(pz.App): def __init__(self): self.query, self.selected = "", 0 self.files = ["src/app.rs", "src/render.rs", "README.md"] def view(self): matches = ui.fuzzy_filter(self.query, self.files) items = [(ui.PaletteItem(f, lambda f=f: self.open(f), icon="file"), positions) for f, positions in matches[:50]] return ui.picker(self.query, lambda q: setattr(self, "query", q), items, selected=self.selected, placeholder="Search files…") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Results ```python files = ["src/app.rs", "src/render.rs", "app.py"] items = ui.fuzzy_filter("app", [ui.PaletteItem(f, on_open, icon="file-code") for f in files], key=lambda item: item.label) ui.picker("app", on_query, items, width=380) ``` ```python ui.picker("zzz", on_query, [], empty_text="No files match", width=380) ``` ```python ui.picker("", on_query, [(ui.PaletteItem("main", on_open, icon="git-branch", detail="2 hours ago"), []), (ui.PaletteItem("docs", on_open, icon="git-branch", detail="yesterday"), [])], width=380) ``` ##### Highlight ```python t = pz.theme.current() score, positions = ui.fuzzy_match("tgsw", "editor: toggle soft wrap") ui.highlighted("editor: toggle soft wrap", positions, color=t.text, match_color=t.accent, size=15) ``` #### Examples ##### Highlighting matches `fuzzy_match` returns `(score, positions)` or `None`; `highlighted` paints those positions. **Code:** ```python t = pz.theme.current() score, positions = ui.fuzzy_match("tgsw", "editor: toggle soft wrap") ui.highlighted("editor: toggle soft wrap", positions, color=t.text, match_color=t.accent, size=16) ``` #### Events Picker has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_query` | `(text)` | Callable that receives the new text. | | `on_submit` | `()` | Message or callable sent when Enter is pressed. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Finder(pz.App): def __init__(self): self.query, self.opened = "", None self.files = ["src/app.rs", "src/render.rs", "README.md"] def matches(self): return ui.fuzzy_filter(self.query, self.files) def open_first(self): # on_submit: Enter found = self.matches() self.opened = found[0][0] if found else None def view(self): items = [(ui.PaletteItem(f, lambda f=f: setattr(self, "opened", f), icon="file"), positions) for f, positions in self.matches()] return ui.picker(self.query, lambda q: setattr(self, "query", q), items, # on_query on_submit=self.open_first, placeholder="Search files…") ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Query: text: str @dataclass class Open: path: str class Finder(pz.App): query, opened = "", None files = ["src/app.rs", "src/render.rs", "README.md"] def update(self, message): match message: case Query(text): self.query = text case Open(path): self.opened = path def view(self): items = [(ui.PaletteItem(f, Open(f), icon="file"), p) for f, p in ui.fuzzy_filter(self.query, self.files)] return ui.picker(self.query, Query, items, placeholder="Search files…") ``` **Functional:** ```python from dataclasses import dataclass FILES = ["src/app.rs", "src/render.rs", "README.md"] @dataclass(frozen=True) class State: query: str = "" opened: str = "" def view(state, set_state): items = [(ui.PaletteItem(f, lambda f=f: set_state(opened=f), icon="file"), p) for f, p in ui.fuzzy_filter(state.query, FILES)] return ui.picker(state.query, lambda q: set_state(query=q), items, placeholder="Search files…") ``` #### Properties and API ##### `ui.picker` ```python picker( query, on_query, items, *, selected=0, placeholder='Search…', input_id='picker', on_submit=None, width=560, max_height=340, empty_text='No matches', theme=None, ) ``` A searchable list on a floating surface. The basis of the palette and the file finder. | Property | Default | Description | | --- | --- | --- | | `query` | *required* | Search text. | | `items` | *required* | `(PaletteItem, positions)` pairs, for example from `fuzzy_filter`. | | `selected` | `0` | Highlighted index. | | `placeholder` | `"Search…"` | Hint text shown when empty. | | `input_id` | `"picker"` | Field id. | | `width` | `560` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `max_height` | `340` | Maximum height in pixels. | | `empty_text` | `"No matches"` | Text shown when there are no results. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_query`, `on_submit` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#picker) ##### `ui.fuzzy_filter` ```python fuzzy_filter(query, items, key=) ``` Filters and sorts `items` by fuzzy score. Returns `[(item, positions), ...]`. | Property | Default | Description | | --- | --- | --- | | `query` | *required* | Search text. | | `items` | *required* | Items. | | `key` | `` | Function that returns the text of each item. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#fuzzy_filter) ##### `ui.fuzzy_match` ```python fuzzy_match(query, candidate) ``` Returns `(score, positions)` if every letter of `query` appears in order in `candidate`; otherwise `None`. Rewards word starts and consecutive letters. | Property | Default | Description | | --- | --- | --- | | `query` | *required* | Search text. | | `candidate` | *required* | Candidate text. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#fuzzy_match) ##### `ui.highlighted` ```python highlighted(text, positions, *, color, match_color, size=13.5, weight=None) ``` Text with the characters at `positions` highlighted (fuzzy search matches). | Property | Default | Description | | --- | --- | --- | | `text` | *required* | Text. | | `positions` | *required* | Indices to highlight. | | `color` | *required* | Text or icon color. | | `match_color` | *required* | Color of the matches. | | `size` | `13.5` | Size. | | `weight` | `None` | Text weight. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#highlighted) #### Related - [Command palette](https://albakore.github.io/pyzed/library/command-palette/): A command palette with fuzzy search and shortcuts. - [Search input](https://albakore.github.io/pyzed/library/search-input/): An input with a magnifying glass, for filtering. - [Layer](https://albakore.github.io/pyzed/library/layer/): Draws an overlay over your view; clicking outside dismisses it. ### Plan > An agent's plan as a checklist that folds. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/plan/ :::tip[In plain words] A to-do list an AI assistant writes for itself and ticks off as it works. ::: `ui.Plan` is a component that shows an AI agent's plan as a checklist: each step is pending (an empty circle), in progress (a dot, or a spinner with `running=True`) or done (a green check, with its text dimmed), and the header counts `done/total`. Clicking the header folds and unfolds the steps. `steps` are dicts with `step` (the text) and `status`: `"pending"`, `"in_progress"` or `"done"`. `ui.Plan` · Category: [AI agents](https://albakore.github.io/pyzed/library/#ai-agents) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#plan) **Code:** ```python pz.container(ui.Plan(steps=[ {"step": "Read the form and its handlers", "status": "done"}, {"step": "Add the email field", "status": "done"}, {"step": "Validate the email as you type", "status": "in_progress"}, {"step": "Run the tests", "status": "pending"}, ], running=True), width=420) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - Above an agent's chat, while it works through a task of several steps. - For any list of steps that updates as the work goes on, such as an install or a migration. #### Usage ```python import pyzed as pz from pyzed import ui class Agent(pz.App): def __init__(self): self.steps = [{"step": "Add the form", "status": "done"}, {"step": "Wire the events", "status": "in_progress"}] self.working = True def view(self): return ui.Plan(steps=self.steps, running=self.working) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### State Without `running` the step in progress shows a dot; folded is drawn as after a click on the header. ```python pz.container(ui.Plan(steps=[{"step": "Add the form", "status": "done"}, {"step": "Wire the events", "status": "in_progress"}, {"step": "Run the tests", "status": "pending"}], running=True), width=300) ``` ```python pz.container(ui.Plan(steps=[{"step": "Add the form", "status": "done"}, {"step": "Wire the events", "status": "in_progress"}, {"step": "Run the tests", "status": "pending"}]), width=300) ``` ```python pz.container(ui.Plan(steps=[{"step": "Add the form", "status": "pending"}, {"step": "Run the tests", "status": "pending"}]), width=300) ``` ```python pz.container(ui.Plan(steps=[{"step": "Add the form", "status": "done"}, {"step": "Run the tests", "status": "done"}]), width=300) ``` ```python pz.container(ui.Plan(steps=[{"step": "Add the form", "status": "done"}, {"step": "Run the tests", "status": "pending"}]), width=300) ``` #### Events Plan has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. #### Properties and API ##### `ui.Plan` ```python class Plan ``` A component for an agent's plan: a checklist with `done/total` in its header, which folds it. | Property | Default | Description | | --- | --- | --- | | `steps` | `None` | `{"step": text, "status": "pending" \| "in_progress" \| "done"}` dicts. | | `running` | `False` | Spins the step in progress. | | `theme` | `None` | Theme. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#plan) #### Related - [Tool call](https://albakore.github.io/pyzed/library/tool-call/): One step of an AI agent: what it did, its result, and Allow or Reject. - [Progress](https://albakore.github.io/pyzed/library/progress/): A thin progress bar in a semantic color. - [Edits bar](https://albakore.github.io/pyzed/library/edits-bar/): The files an agent changed, with Keep all and Reject all. ### Popover > Floating content at a point: context menus, color pickers. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/popover/ :::tip[In plain words] A small floating box that appears next to where you clicked, like a right-click menu. ::: Shows `content` (a menu, a card…) over `base` at `(x, y)`. Clicking anywhere else calls `on_dismiss`; with `content=None` only `base` is shown. For a right-click menu, store the pointer position with `pz.mouse_area(on_move=...)` and open it from `on_right_press`. `ui.popover` · Category: [Overlays](https://albakore.github.io/pyzed/library/#overlays) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#popover) **Code:** ```python ui.popover( main_view(), ui.menu([ ui.MenuItem("Copy", on_copy, icon="copy", keys="ctrl-c"), ui.MenuItem("Paste", on_paste, icon="clipboard", keys="ctrl-v"), ui.SEPARATOR, ui.MenuItem("Delete", on_delete, icon="trash-2", danger=True), ], width=220), x=180, y=70, on_dismiss=on_close, ) ``` #### When to use - For context menus, dropdown panels and pickers anchored to a point or a button. #### Usage ```python import pyzed as pz from pyzed import ui class Canvas(pz.App): def __init__(self): self.pointer, self.menu_at = (0, 0), None def view(self): base = pz.mouse_area(self.content(), on_move=lambda x, y: setattr(self, "pointer", (x, y)), on_right_press=lambda: setattr(self, "menu_at", self.pointer)) menu = ui.menu([ui.MenuItem("Copy", self.copy), ui.MenuItem("Paste", self.paste)]) x, y = self.menu_at or (0, 0) return ui.popover(base, menu if self.menu_at else None, x=x, y=y, on_dismiss=lambda: setattr(self, "menu_at", None)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python ui.popover(main_view(), ui.menu([ui.MenuItem("Copy", on_copy, icon="copy"), ui.MenuItem("Paste", on_paste, icon="clipboard")], width=180), x=60, y=40, on_dismiss=on_close) ``` ```python ui.popover(main_view(), ui.card(ui.muted("Any widget fits here."), title="Popover", width=220), x=120, y=40, on_dismiss=on_close) ``` #### Events Popover has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_dismiss` | `()` | Message or callable sent on close. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Canvas(pz.App): def __init__(self): self.pointer, self.menu_at = (0, 0), None def view(self): base = pz.mouse_area(main_view(), on_move=lambda x, y: setattr(self, "pointer", (x, y)), on_right_press=lambda: setattr(self, "menu_at", self.pointer)) menu = ui.menu([ui.MenuItem("Copy", lambda: setattr(self, "menu_at", None))]) x, y = self.menu_at or (0, 0) return ui.popover(base, menu if self.menu_at else None, x=x, y=y, on_dismiss=lambda: setattr(self, "menu_at", None)) # click outside ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class MenuAt: x: float y: float class Canvas(pz.App): menu_at = None def update(self, message): match message: case MenuAt(x, y): self.menu_at = (x, y) case "close": self.menu_at = None def view(self): base = pz.canvas([], width=400, height=200, on_right_press=MenuAt) x, y = self.menu_at or (0, 0) return ui.popover(base, ui.menu([ui.MenuItem("Copy", "close")]) if self.menu_at else None, x=x, y=y, on_dismiss="close") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: menu_at: tuple = () def view(state, set_state): base = pz.canvas([], width=400, height=200, on_right_press=lambda x, y: set_state(menu_at=(x, y))) menu = ui.menu([ui.MenuItem("Copy", lambda: set_state(menu_at=()))]) if state.menu_at else None x, y = state.menu_at or (0, 0) return ui.popover(base, menu, x=x, y=y, on_dismiss=lambda: set_state(menu_at=())) ``` #### Properties and API ##### `ui.popover` ```python popover(base, content=None, *, x=0, y=0, on_dismiss=None, align_x='start') ``` Shows `content` (a `ui.menu`, a card…) over `base` at `(x, y)`. Clicking anywhere else calls `on_dismiss`. For a right-click menu, store the mouse position with `mouse_area(on_move=...)` and open the popover from `on_right_press` (see `examples/context_menu.py`). | Property | Default | Description | | --- | --- | --- | | `base` | *required* | The UI underneath. | | `content` | `None` | What floats (or `None`). | | `x` | `0` | Horizontal position. | | `y` | `0` | Vertical position. | | `align_x` | `"start"` | Horizontal alignment: `"start"`/`"left"`, `"center"`, `"end"`/`"right"`. | Events: `on_dismiss` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#popover) #### Related - [Menu](https://albakore.github.io/pyzed/library/menu/): A context menu with icons, shortcuts and checks. - [Layer](https://albakore.github.io/pyzed/library/layer/): Draws an overlay over your view; clicking outside dismisses it. - [Split button](https://albakore.github.io/pyzed/library/split-button/): A main action plus an arrow that opens more options. ### Progress > A thin progress bar in a semantic color. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/progress/ :::tip[In plain words] A bar that fills up to show how much of a task is done. ::: A thin bar that fills from `0` to `max` (1.0 by default). `tint` changes its color and `height` its thickness. `ui.progress` · Category: [Feedback](https://albakore.github.io/pyzed/library/#feedback) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#progress) **Code:** ```python pz.column([ ui.progress(0.25), ui.progress(0.6, tint="success", height=6), ui.progress(37, max=40, tint="warning", height=8), ], spacing=18, width=360) ``` #### When to use - For work whose progress you can measure: downloads, builds, imports. - When you can't measure it, show a [Spinner](https://albakore.github.io/pyzed/library/spinner/). #### Usage ```python import pyzed as pz from pyzed import ui class Download(pz.App): def __init__(self): self.done, self.total = 0, 1 def update(self, message): self.done, self.total = message # posted from a worker thread with pz.post((done, total)) def view(self): return ui.progress(self.done, max=self.total) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Value ```python ui.progress(0.1, width=240) ``` ```python ui.progress(0.5, width=240) ``` ```python ui.progress(1.0, width=240) ``` ```python ui.progress(37, max=40, width=240) ``` ##### Tint ```python ui.progress(0.7, tint="success", width=240) ``` ```python ui.progress(0.7, tint="warning", width=240) ``` ```python ui.progress(0.7, tint="error", width=240) ``` ##### Thickness ```python ui.progress(0.6, height=2, width=240) ``` ```python ui.progress(0.6, height=4, width=240) ``` ```python ui.progress(0.6, height=10, width=240) ``` ##### States and events ```python pz.container(ui.progress(0.42, label="Downloading", show_value=True), width=300) ``` ```python pz.container(ui.progress(None, label="Indexing"), width=300) ``` ##### Base widget The `pz.*` widget underneath: no theme, every color and size is yours. ```python pz.progress_bar(64, max=100, width=240, height=12, accent="#c678dd", bg="#c678dd33", radius=6) ``` #### Events Progress has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.progress` ```python progress( value, *, max=1.0, tint='accent', height=4, width='fill', label=None, show_value=False, theme=None, ) ``` A thin progress bar. | Property | Default | Description | | --- | --- | --- | | `value` | *required* | Progress, or `None` for an indeterminate bar (keep a `pz.every(1/30, ...)` subscription while it shows). | | `max` | `1.0` | Maximum value. | | `tint` | `"accent"` | Semantic color: `"accent"`, `"error"`, `"warning"`, `"success"`, `"info"` or a token. | | `height` | `4` | Thickness. | | `width` | `"fill"` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `label` | `None` | Text above the bar. | | `show_value` | `False` | Adds the percentage at its right. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#progress) ##### `pz.progress_bar` ```python progress_bar( value, *, min=0.0, max=1.0, width=None, height=None, accent=None, bg=None, radius=2.0, ) ``` A progress bar. | Property | Default | Description | | --- | --- | --- | | `value` | *required* | Current value. | | `min` | `0.0` | Minimum. | | `max` | `1.0` | Maximum. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `accent` | `None` | Accent color (active part). | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `radius` | `2.0` | Corner radius. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#progress_bar) #### Related - [Spinner](https://albakore.github.io/pyzed/library/spinner/): A spinning arc for loading states. - [Slider](https://albakore.github.io/pyzed/library/slider/): Pick a number in a range by dragging. - [Stat](https://albakore.github.io/pyzed/library/stat/): A dashboard number with change and sparkline. ### Prompt > Asks for a line of text. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/prompt/ :::tip[In plain words] A small box that asks you to type something, like a new name for a file. ::: Asks for a line of text: a controlled input plus Cancel and OK. Enter or the button calls `on_submit`. `ui.prompt` · Category: [Dialogs](https://albakore.github.io/pyzed/library/#dialogs) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#prompt) **Code:** ```python ui.dialog_layer(main_view(), ui.prompt( "Rename", "notes.py", on_input, on_submit, on_cancel, message="New name for the file:", width=360, )) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For quick names: rename a file, name a new branch, save a view. #### Usage ```python import pyzed as pz from pyzed import ui class Files(pz.App): def __init__(self): self.new_name = None def view(self): dialog = None if self.new_name is not None: dialog = ui.prompt("Rename", self.new_name, lambda t: setattr(self, "new_name", t), self.rename, lambda: setattr(self, "new_name", None)) return ui.dialog_layer(self.main_view(), dialog) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python ui.prompt("New branch", "", on_input, on_submit, on_cancel, placeholder="feature/…", width=340) ``` ```python ui.prompt("Rename", "notes.py", on_input, on_submit, on_cancel, message="New name for the file:", width=340) ``` ```python ui.prompt("Save view", "My view", on_input, on_submit, on_cancel, submit_label="Save", width=340) ``` #### Events Prompt has **3 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_input` | `(text)` | Receives each edit. | | `on_submit` | `()` | Enter or the submit button. | | `on_cancel` | `()` | Cancel, the close icon. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Files(pz.App): def __init__(self): self.name = "notes.py" self.new_name = "notes.py" # None while the dialog is closed def rename(self): # on_submit: Enter or the button self.name, self.new_name = self.new_name, None def view(self): dialog = None if self.new_name is not None: dialog = ui.prompt("Rename", self.new_name, lambda text: setattr(self, "new_name", text), # on_input self.rename, lambda: setattr(self, "new_name", None), # on_cancel message="New name for the file:") return ui.dialog_layer(main_view(), dialog) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Typed: text: str class Files(pz.App): name, new_name = "notes.py", "notes.py" def update(self, message): match message: case Typed(text): self.new_name = text case "rename": self.name, self.new_name = self.new_name, None case "cancel": self.new_name = None def view(self): dialog = ui.prompt("Rename", self.new_name, Typed, "rename", "cancel") \ if self.new_name is not None else None return ui.dialog_layer(main_view(), dialog) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: name: str = "notes.py" draft: str = "notes.py" renaming: bool = True def view(state, set_state): if not state.renaming: return ui.label(state.name) return ui.dialog_layer(main_view(), ui.prompt( "Rename", state.draft, lambda text: set_state(draft=text), lambda: set_state(name=state.draft, renaming=False), lambda: set_state(renaming=False))) ``` #### Properties and API ##### `ui.prompt` ```python prompt( title, value, on_input, on_submit, on_cancel, *, message=None, placeholder='', submit_label=None, cancel_label=None, id=None, width=440, theme=None, ) ``` Asks for a line of text. | Property | Default | Description | | --- | --- | --- | | `title` | *required* | Title. | | `value` | *required* | Current text. | | `message` | `None` | Text above the field. | | `placeholder` | `""` | Hint text shown when empty. | | `submit_label` | `None` | Submit button text. | | `cancel_label` | `None` | Cancel button text. | | `id` | `None` | Field id (for `Command.focus`). | | `width` | `440` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_input`, `on_submit`, `on_cancel` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#prompt) #### Related - [Confirm](https://albakore.github.io/pyzed/library/confirm/): A yes/no question, red for destructive actions. - [Input](https://albakore.github.io/pyzed/library/input/): A controlled text field with icon, placeholder and password mode. - [Dialog layer](https://albakore.github.io/pyzed/library/dialog-layer/): Centers a dialog over your view with a dimmed backdrop. ### QR code > A QR code for any text or URL. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/qr-code/ :::tip[In plain words] A square barcode a phone camera can read, for sharing a link. ::: Draws a QR code that encodes `data`. `cell_size` sets the size of each module; `color` and `bg` change its colors. `pz.qr_code` · Category: [Content](https://albakore.github.io/pyzed/library/#content) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#qr_code) **Code:** ```python pz.row([ pz.qr_code("https://albakore.github.io/pyzed/", cell_size=5), pz.qr_code("pyzed", cell_size=5, color="#74ade8", bg="#282c33"), ], spacing=24, align="center") ``` #### When to use - To pass a link, a Wi-Fi password or a pairing code to a phone. #### Usage ```python import pyzed as pz pz.row([ pz.qr_code("https://albakore.github.io/pyzed/", cell_size=5), pz.qr_code("pyzed", cell_size=5, color="#74ade8", bg="#282c33"), ], spacing=24, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python pz.qr_code("https://albakore.github.io/pyzed/", cell_size=3) ``` ```python pz.qr_code("pyzed", cell_size=5) ``` ```python pz.qr_code("pyzed", cell_size=5, color="#74ade8", bg="#1e2228") ``` #### Events QR code has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.qr_code` ```python qr_code(data, *, cell_size=4.0, color=None, bg=None) ``` A QR code that encodes `data`. | Property | Default | Description | | --- | --- | --- | | `data` | *required* | The text or URL to encode. | | `cell_size` | `4.0` | Size of each module in pixels. | | `color` | `None` | Text or icon color. | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#qr_code) #### Related - [Image](https://albakore.github.io/pyzed/library/image/): Bitmaps with fit, opacity, radius; a pan-and-zoom viewer. - [Canvas](https://albakore.github.io/pyzed/library/canvas/): 2D drawing with shapes, paths, text and mouse events. ### Radio group > Mutually exclusive options as radio buttons. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/radio-group/ :::tip[In plain words] A few round options where picking one unpicks the others. ::: A set of radio buttons where one option is selected. `options` are strings or `(value, label)` pairs; `on_select` receives the value. `horizontal=True` lays them out in a row. `ui.radio_group` · Category: [Forms](https://albakore.github.io/pyzed/library/#forms) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#radio_group) **Code:** ```python pz.row([ ui.radio_group(["Spaces", "Tabs"], "Spaces", on_select), ui.radio_group([("lf", "LF"), ("crlf", "CRLF"), ("cr", "CR")], "lf", on_select, horizontal=True), ], spacing=40, align="center") ``` #### When to use - When the options need a label each and should all be visible (indentation: spaces or tabs). - For many options use a [Select](https://albakore.github.io/pyzed/library/select/). #### Usage ```python import pyzed as pz from pyzed import ui class Settings(pz.App): def __init__(self): self.indent = "spaces" def view(self): return ui.radio_group([("spaces", "Spaces"), ("tabs", "Tabs")], self.indent, lambda value: setattr(self, "indent", value)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Direction ```python ui.radio_group(["Spaces", "Tabs"], "Spaces", on_select) ``` ```python ui.radio_group(["LF", "CRLF", "CR"], "LF", on_select, horizontal=True) ``` ```python ui.radio_group(["Small", "Medium", "Large"], "Medium", on_select, horizontal=True, spacing=16) ``` ##### Options ```python ui.radio_group([("lf", "Unix (LF)"), ("crlf", "Windows (CRLF)")], "crlf", on_select) ``` ```python ui.radio_group(["Yes", "No"], None, on_select, horizontal=True) ``` ##### States and events ```python ui.radio_group(["LF", "CRLF", "CR"], "LF", on_select, horizontal=True, disabled={"CR"}) ``` ```python ui.radio_group(["Spaces", "Tabs"], "Spaces", on_select, descriptions={"Spaces": "Indent with 4 spaces", "Tabs": "One tab per level"}) ``` ##### Base widget The `pz.*` widget underneath: no theme, every color and size is yours. ```python pz.row([pz.radio("Cats", True, on_select, accent="#e5c07b"), pz.radio("Dogs", False, on_select, accent="#e5c07b")], spacing=16) ``` #### Events Radio group has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_select` | `ui.radio_group`, `pz.radio` | `(value)` | Callable that receives the chosen value. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Settings(pz.App): def __init__(self): self.indent = "spaces" def set_indent(self, value): # on_select gets the value, not the label self.indent = value def view(self): return ui.radio_group([("spaces", "Spaces"), ("tabs", "Tabs")], self.indent, self.set_indent) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Indent: value: str class Settings(pz.App): indent = "spaces" def update(self, message): match message: case Indent(value): self.indent = value def view(self): return ui.radio_group([("spaces", "Spaces"), ("tabs", "Tabs")], self.indent, Indent) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: indent: str = "spaces" def view(state, set_state): return ui.radio_group([("spaces", "Spaces"), ("tabs", "Tabs")], state.indent, lambda value: set_state(indent=value), horizontal=True) ``` #### Tips :::tip Once clicked or reached with Tab the group has the keyboard focus: the arrows pick the previous or next choice (skipping disabled ones) and Home/End the first and last. ::: #### Properties and API ##### `ui.radio_group` ```python radio_group( options, selected, on_select=None, *, horizontal=False, spacing=8, disabled=False, descriptions=None, id=None, theme=None, ) ``` Mutually exclusive options as radio buttons. | Property | Default | Description | | --- | --- | --- | | `options` | *required* | Strings or `(value, label)` pairs. | | `selected` | *required* | Current value. | | `horizontal` | `False` | In a row instead of a column. | | `spacing` | `8` | Space between children, in pixels. | | `disabled` | `False` | `True`, or the values to disable. | | `descriptions` | `None` | Maps values to a muted line under their label. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_select` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#radio_group) ##### `pz.radio` ```python radio( label, selected, on_select=None, *, size=None, text_size=None, spacing=None, accent=None, bg=None, border_color=None, color=None, ) ``` A radio button. Group several yourself (or use `ui.radio_group`); `on_select` is sent when it is clicked. | Property | Default | Description | | --- | --- | --- | | `label` | *required* | Label text. | | `selected` | *required* | Whether it is checked. | | `size` | `None` | Size. | | `text_size` | `None` | Text size. | | `spacing` | `None` | Space between the circle and the text. | | `accent` | `None` | Accent color (active part). | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `border_color` | `None` | Border color. | | `color` | `None` | Text or icon color. | Events: `on_select` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#radio) #### Related - [Segmented](https://albakore.github.io/pyzed/library/segmented/): A group of mutually exclusive text buttons. - [Select](https://albakore.github.io/pyzed/library/select/): A dropdown to choose one option. - [Checkbox](https://albakore.github.io/pyzed/library/checkbox/): A checkbox with an optional label. ### Reference browser > Built-in, searchable docs like Godot's: a class list next to the open page. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/reference-browser/ :::tip[In plain words] A help window with the documentation inside the app, searchable and offline. ::: The built-in reference: a searchable class list (the library, your components and any section you `reference.register`) next to the page that is open, with back and forward, internal links and an Open online button. Keep a `pyzed.reference.Browser` in your state; the browser changes it. Links that leave the reference go to `on_open_url`. See [Built-in reference](https://albakore.github.io/pyzed/editor/reference/). `ui.reference_browser` · Category: [Code and tools](https://albakore.github.io/pyzed/library/#code-and-tools) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#reference_browser) **Code:** ```python from pyzed import reference help = reference.Browser("pyzed.ui.button") ui.reference_browser(help, on_open_url=open_in_browser, sidebar_width=230) ``` #### When to use - In a Help tab or window of an app built on Pyzed, so its users can read the API offline. - With your own `reference.Provider` sections, as your app's help. #### Usage ```python from pyzed import ui from pyzed import reference help = reference.Browser("pyzed.ui.button") ui.reference_browser(help, on_open_url=open_in_browser, sidebar_width=230) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Pages ```python from pyzed import reference ui.reference_browser(reference.Browser("pyzed.ui.badge"), sidebar_width=200) ``` ```python from pyzed import reference ui.reference_browser(reference.Browser("pyzed.row"), sidebar_width=200) ``` #### Events Reference browser has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_open_url` | `(url)` | Called with the URL of a link that leaves the reference (open it in the browser). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python import webbrowser from pyzed import reference class Help(pz.App): def __init__(self): self.browser = reference.Browser("pyzed.ui.button") def view(self): return ui.reference_browser(self.browser, on_open_url=webbrowser.open) # links to the web ``` **Declarative:** ```python from dataclasses import dataclass from pyzed import reference @dataclass class OpenUrl: url: str class Help(pz.App): browser = reference.Browser("pyzed.ui.button") def update(self, message): match message: case OpenUrl(url): print("open", url) def view(self): return ui.reference_browser(self.browser, on_open_url=OpenUrl) ``` **Functional:** ```python from dataclasses import dataclass from pyzed import reference BROWSER = reference.Browser("pyzed.ui.button") @dataclass(frozen=True) class State: last_url: str = "" def view(state, set_state): return ui.reference_browser(BROWSER, on_open_url=lambda url: set_state(last_url=url)) ``` #### Properties and API ##### `ui.reference_browser` ```python reference_browser( browser, *, on_open_url=None, sidebar_width=270, width='fill', height='fill', theme=None, ) ``` The built-in reference, like Godot's: a searchable class list next to the page that is open. Events: `on_open_url` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#reference_browser) #### Related - [Shortcuts](https://albakore.github.io/pyzed/library/shortcuts/): A searchable list of key bindings, grouped. - [About](https://albakore.github.io/pyzed/library/about/): An About box with icon, version, details and links. - [Markdown](https://albakore.github.io/pyzed/library/markdown/): Renders Markdown with the theme's colors. ### Resizable > A panel whose edge can be dragged to resize it. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/resizable/ :::tip[In plain words] A panel with an edge you can drag to make it bigger or smaller. ::: A panel whose `edge` (`"left"`, `"right"`, `"top"` or `"bottom"`) can be dragged to resize it, between `min_size` and `max_size`. It keeps the size the user drags it to; `on_resize(size)` is called when the drag ends so you can save it. `pz.resizable` · Category: [Layout](https://albakore.github.io/pyzed/library/#layout) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#resizable) **Code:** ```python t = pz.theme.current() pz.row([ pz.resizable(pz.container(ui.label("Drag my right edge"), padding=12, width="fill", height="fill", bg=t.panel), edge="right", size=260, min_size=160, color=t.border, hover_color=t.accent), pz.container(ui.muted("Content"), center=True, width="fill", height="fill"), ], height="fill") ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For one resizable sidebar or bottom panel next to fixed content. #### Usage ```python import pyzed as pz from pyzed import ui t = pz.theme.current() pz.row([ pz.resizable(pz.container(ui.label("Drag my right edge"), padding=12, width="fill", height="fill", bg=t.panel), edge="right", size=260, min_size=160, color=t.border, hover_color=t.accent), pz.container(ui.muted("Content"), center=True, width="fill", height="fill"), ], height="fill") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Edge ```python t = pz.theme.current() pz.row([pz.resizable(pz.container(ui.label("Sidebar"), padding=10, width="fill", height="fill", bg=t.panel), edge="right", size=150, color=t.border), pz.container(width="fill")], height="fill") ``` ```python t = pz.theme.current() pz.row([pz.container(width="fill"), pz.resizable(pz.container(ui.label("Inspector"), padding=10, width="fill", height="fill", bg=t.panel), edge="left", size=150, color=t.border)], height="fill") ``` ```python t = pz.theme.current() pz.column([pz.container(height="fill"), pz.resizable(pz.container(ui.label("Console"), padding=10, width="fill", height="fill", bg=t.panel), edge="top", size=80, color=t.border)], width="fill") ``` #### Events Resizable has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_resize` | `(size)` | Called with the new size when a drag ends. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Mail(pz.App): def __init__(self): self.width = 260 def view(self): return pz.row([ pz.resizable(ui.muted(f"{self.width:.0f} px"), edge="right", size=self.width, min_size=160, on_resize=lambda size: setattr(self, "width", size)), # when the drag ends main_view(), ], height="fill") ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Width: size: float class Mail(pz.App): width = 260 def update(self, message): match message: case Width(size): self.width = size def view(self): return pz.row([pz.resizable(ui.muted("Folders"), size=self.width, on_resize=Width), main_view()], height="fill") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: width: float = 260 def view(state, set_state): return pz.row([pz.resizable(ui.muted("Folders"), size=state.width, on_resize=lambda size: set_state(width=size)), main_view()], height="fill") ``` #### Properties and API ##### `pz.resizable` ```python resizable( content, *, edge='right', size=240.0, min_size=80.0, max_size=None, on_resize=None, color=None, hover_color=None, thickness=1.0, handle=8.0, width=None, height=None, ) ``` A panel whose `edge` can be dragged to resize it. It keeps the size the user drags it to; `on_resize(size)` is called when a drag ends so you can save it. Changing `size` later resets it. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | The panel's content. | | `edge` | `"right"` | The edge with the handle: `"right"` (a left sidebar), `"left"`, `"top"` (a bottom panel) or `"bottom"`. | | `size` | `240.0` | Starting width (height for top/bottom edges). | | `min_size` | `80.0` | Smallest size. | | `max_size` | `None` | Largest size. | | `color` | `None` | Line color. | | `hover_color` | `None` | Line color while hovered or dragged. | | `thickness` | `1.0` | Line thickness. | | `handle` | `8.0` | Width of the area that can be grabbed. | | `width` | `None` | Width for top/bottom edges. | | `height` | `None` | Height for left/right edges. | Events: `on_resize` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#resizable) #### Related - [Split](https://albakore.github.io/pyzed/library/split/): Two panes with a draggable divider. - [Panel](https://albakore.github.io/pyzed/library/panel/): A dockable, resizable side panel. ### Responsive > Builds its content from the space actually available. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/responsive/ :::tip[In plain words] Changes the layout depending on how much room there is, like a phone versus a monitor. ::: Calls `function(width, height)` with the space it really gets and shows what it returns, so the layout can adapt: hide a sidebar when the window is narrow, change the number of columns… `pz.responsive` · Category: [Layout](https://albakore.github.io/pyzed/library/#layout) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#responsive) **Code:** ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.responsive(lambda w, h: pz.center(pz.column([ ui.muted(f"{w:.0f} × {h:.0f} px available"), pz.row([box("1"), box("2"), box("3"), box("4")], spacing=8) if w > 400 else pz.column([box("1"), box("2")], spacing=8), ], spacing=10, align="center"))), width=480, height=150) ``` #### When to use - For layouts that must work both in a small and a large window. #### Usage ```python import pyzed as pz from pyzed import ui box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.responsive(lambda w, h: pz.center(pz.column([ ui.muted(f"{w:.0f} × {h:.0f} px available"), pz.row([box("1"), box("2"), box("3"), box("4")], spacing=8) if w > 400 else pz.column([box("1"), box("2")], spacing=8), ], spacing=10, align="center"))), width=480, height=150) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Available width The same code, given two widths: the layout changes by itself. ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.responsive(lambda w, h: pz.row([box("1"), box("2"), box("3")], spacing=8) if w > 300 else pz.column([box("1"), box("2")], spacing=8)), width=200, height=110) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.container(pz.responsive(lambda w, h: pz.row([box("1"), box("2"), box("3")], spacing=8) if w > 300 else pz.column([box("1"), box("2")], spacing=8)), width=400, height=60) ``` #### Events Responsive has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.responsive` ```python responsive(function) ``` Builds its content with `function(width, height)` using the space actually available, so the layout can adapt (for example, hiding a sidebar when the window is narrow). | Property | Default | Description | | --- | --- | --- | | `function` | *required* | Function that receives `(width, height)` and returns a widget. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#responsive) #### Related - [Grid](https://albakore.github.io/pyzed/library/grid/): Equal columns, or CSS-like tracks with spans. - [Flex](https://albakore.github.io/pyzed/library/flex/): CSS flexbox: justify, align, gap, wrap and grow. ### Rich text > One block of text mixing colors, weights and links. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/rich-text/ :::tip[In plain words] A sentence where some words are bold, colored or links. ::: Combines `pz.span(text, color=, size=, font=, weight=, italic=, bg=, underline=, strikethrough=, link=)` fragments into a single block of text that wraps as a whole. Clicking a span with `link` sends that value. `pz.rich_text` · Category: [Content](https://albakore.github.io/pyzed/library/#content) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#rich_text) **Code:** ```python pz.rich_text([ pz.span("rich_text "), pz.span("mixes ", color="#e5c07b"), pz.span("styles", weight="bold", underline=True), pz.span(" on one line, with "), pz.span(" code ", font="IBM Plex Mono", bg="#3b414d", radius=4), pz.span(" and "), pz.span("links", color="#74ade8", underline=True, link="https://iced.rs"), ], size=18, width=460) ``` #### When to use - For inline highlights, mentions, search matches and short formatted messages. #### Usage ```python import pyzed as pz pz.rich_text([ pz.span("rich_text "), pz.span("mixes ", color="#e5c07b"), pz.span("styles", weight="bold", underline=True), pz.span(" on one line, with "), pz.span(" code ", font="IBM Plex Mono", bg="#3b414d", radius=4), pz.span(" and "), pz.span("links", color="#74ade8", underline=True, link="https://iced.rs"), ], size=18, width=460) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Span styles ```python pz.rich_text([pz.span("Some "), pz.span("bold", weight="bold"), pz.span(" text")], size=16) ``` ```python pz.rich_text([pz.span("Some "), pz.span("italic", italic=True), pz.span(" text")], size=16) ``` ```python pz.rich_text([pz.span("Some "), pz.span("colored", color="#e5c07b"), pz.span(" text")], size=16) ``` ```python pz.rich_text([pz.span("Some "), pz.span("underlined", underline=True), pz.span(" text")], size=16) ``` ```python pz.rich_text([pz.span("Some "), pz.span("struck", strikethrough=True), pz.span(" text")], size=16) ``` ```python pz.rich_text([pz.span("Run "), pz.span(" pyzed new ", font="mono", bg="#3b414d", color="#e6e6e6", radius=4)], size=16) ``` ```python pz.rich_text([pz.span("Read "), pz.span("the docs", color="#74ade8", underline=True, link="https://iced.rs")], size=16) ``` ```python pz.rich_text([pz.span("small ", size=12), pz.span("big", size=24, weight="bold")]) ``` #### Events Rich text has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.rich_text` ```python rich_text( spans, *, size=None, color=None, font=None, line_height=None, width=None, align_x=None, wrap=True, ) ``` Text made of spans with different styles. Plain strings are unstyled spans. | Property | Default | Description | | --- | --- | --- | | `spans` | *required* | List of `span(...)` or strings. | | `size` | `None` | Size. | | `color` | `None` | Text or icon color. | | `font` | `None` | Font of the span or text (family name, e.g. `"IBM Plex Mono"`). | | `line_height` | `None` | Line height. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `align_x` | `None` | Horizontal alignment: `"start"`/`"left"`, `"center"`, `"end"`/`"right"`. | | `wrap` | `True` | Line wrapping / moves children to a new row when they don't fit. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#rich_text) ##### `pz.span` ```python span( text, *, color=None, size=None, font=None, weight=None, italic=False, bg=None, radius=0.0, padding=None, underline=False, strikethrough=False, link=None, ) ``` A styled span for `rich_text`. With `link`, clicking it sends (or calls) that value. | Property | Default | Description | | --- | --- | --- | | `text` | *required* | The text. | | `color` | `None` | Text or icon color. | | `size` | `None` | Size. | | `font` | `None` | Font of the span or text (family name, e.g. `"IBM Plex Mono"`). | | `weight` | `None` | Font weight: `"normal"`, `"medium"`, `"semibold"` or `"bold"`. | | `italic` | `False` | If `True`, the span is drawn in italics. | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `radius` | `0.0` | Background radius. | | `padding` | `None` | Inner padding: `8`, `(vertical, horizontal)` or `(top, right, bottom, left)`. | | `underline` | `False` | Underline. | | `strikethrough` | `False` | Strikethrough. | | `link` | `None` | Message or callable on click. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#span) #### Related - [Text](https://albakore.github.io/pyzed/library/text/): A piece of text with size, color, font and weight. - [Markdown](https://albakore.github.io/pyzed/library/markdown/): Renders Markdown with the theme's colors. ### Row > Lays out children horizontally. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/row/ :::tip[In plain words] Puts things side by side, from left to right. ::: Lays out its children horizontally, with `spacing` between them and `align` on the cross axis. `wrap=True` moves children that don't fit to the next line. Lists are flattened and `None`/`False` are skipped, so `cond and widget` works. `pz.row` · Category: [Layout](https://albakore.github.io/pyzed/library/#layout) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#row) **Code:** ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.column([ pz.row([box("A"), box("B"), box("C")], spacing=8), pz.row([box("Start"), pz.hspace(), box("End")], spacing=8, width=420), pz.row([box("tall", h=70), box("center"), box("end")], spacing=8, align="center"), ], spacing=14) ``` #### When to use - For toolbars, button groups, form rows: anything side by side. - Push items apart with `pz.hspace()` between them. #### Usage ```python import pyzed as pz from pyzed import ui box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.column([ pz.row([box("A"), box("B"), box("C")], spacing=8), pz.row([box("Start"), pz.hspace(), box("End")], spacing=8, width=420), pz.row([box("tall", h=70), box("center"), box("end")], spacing=8, align="center"), ], spacing=14) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Spacing ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.row([box("A"), box("B"), box("C")]) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.row([box("A"), box("B"), box("C")], spacing=8) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.row([box("A"), box("B"), box("C")], spacing=24) ``` ##### Cross-axis alignment ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.row([box("tall", h=70), box("B"), box("C")], spacing=8, align="start") ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.row([box("tall", h=70), box("B"), box("C")], spacing=8, align="center") ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.row([box("tall", h=70), box("B"), box("C")], spacing=8, align="end") ``` ##### Options ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.row([box("Start"), pz.hspace(), box("End")], width=320) ``` ```python pz.container(pz.row([ui.chip(t) for t in ["python", "rust", "iced", "desktop", "gui", "async", "themes"]], spacing=6, wrap=True, line_spacing=6), width=260) ``` #### Examples ##### Wrapping With `wrap=True` children flow onto new lines, like tags. **Code:** ```python pz.container(pz.row([ui.chip(t) for t in ["python", "rust", "iced", "zed", "desktop", "gui", "async", "themes", "canvas", "markdown"]], spacing=6, wrap=True, line_spacing=6), width=360) ``` #### Events Row has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.row` ```python row( children=None, *, spacing=0.0, padding=None, width=None, height=None, align=None, clip=False, wrap=False, line_spacing=None, ) ``` Lays out its children horizontally. | Property | Default | Description | | --- | --- | --- | | `children` | `None` | List of children. Nested lists are flattened and `None` and `False` are ignored, so you can write `cond and widget`. | | `spacing` | `0.0` | Space between children, in pixels. | | `padding` | `None` | Inner padding: `8`, `(vertical, horizontal)` or `(top, right, bottom, left)`. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `align` | `None` | Alignment of the children on the cross axis: `"start"`, `"center"` or `"end"`. | | `clip` | `False` | Clips content that overflows the bounds. | | `wrap` | `False` | Line wrapping / moves children to a new row when they don't fit. | | `line_spacing` | `None` | Space between rows when `wrap=True`. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#row) #### Related - [Column](https://albakore.github.io/pyzed/library/column/): Stacks children vertically. - [Flex](https://albakore.github.io/pyzed/library/flex/): CSS flexbox: justify, align, gap, wrap and grow. - [Space](https://albakore.github.io/pyzed/library/spacing/): Fixed gaps and flexible spacers. ### Scrollable > Scrolls content that doesn't fit. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/scrollable/ :::tip[In plain words] Lets you scroll content that doesn't fit, with a scroll bar. ::: Makes its content scrollable vertically, horizontally or `"both"`. Give it an `id` to scroll from code (`pz.Command.scroll_to`), `anchor_bottom=True` to stick to the end (chats, logs), and style the rail and scroller with the theme or your own colors. `pz.scrollable` · Category: [Layout](https://albakore.github.io/pyzed/library/#layout) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#scrollable) **Code:** ```python pz.container(pz.scrollable( pz.column([ui.list_item(f"Item {i}", on_open, icon="file", inset=True) for i in range(1, 30)]), height=220, ), width=300) ``` #### When to use - For long lists, documents and any content taller than its space. #### Usage ```python import pyzed as pz from pyzed import ui pz.container(pz.scrollable( pz.column([ui.list_item(f"Item {i}", on_open, icon="file", inset=True) for i in range(1, 30)]), height=220, ), width=300) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Direction ```python pz.container(pz.scrollable(pz.column([ui.list_item(f"Item {i}", icon="file", inset=True) for i in range(1, 30)]), height=130), width=240) ``` ```python pz.container(pz.scrollable(pz.container(pz.row([ui.chip(f"tag {i}") for i in range(1, 25)], spacing=6), padding=(0, 0, 14, 0)), direction="horizontal"), width=300) ``` #### Events Scrollable has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_scroll` | `(info)` | Callable that receives a dict with `x`, `y`, `relative_x`, `relative_y`, `width`, `height`, `content_width` and `content_height`. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Feed(pz.App): def __init__(self): self.items = [f"Post {i}" for i in range(1, 30)] self.at_end = False def scrolled(self, info): # on_scroll: x, y, relative_x, relative_y, sizes self.at_end = info["relative_y"] > 0.95 def view(self): return pz.column([ pz.scrollable(pz.column([ui.list_item(p, icon="file") for p in self.items]), height=200, on_scroll=self.scrolled), ui.muted("You reached the end" if self.at_end else "Scroll down"), ], spacing=6, width=300) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Scrolled: info: dict class Feed(pz.App): items = [f"Post {i}" for i in range(1, 30)] def update(self, message): match message: case Scrolled(info) if info["relative_y"] > 0.95: self.items = self.items + [f"Post {len(self.items) + 1}"] # load more def view(self): return pz.scrollable(pz.column([ui.list_item(p) for p in self.items]), height=200, on_scroll=Scrolled) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: progress: float = 0.0 def view(state, set_state): return pz.column([ ui.progress(state.progress), pz.scrollable(pz.column([ui.list_item(f"Post {i}") for i in range(30)]), height=200, on_scroll=lambda info: set_state(progress=info["relative_y"])), ], spacing=6, width=300) ``` #### Properties and API ##### `pz.scrollable` ```python scrollable( content, *, direction='vertical', width=None, height=None, padding=None, id=None, anchor_bottom=False, rail=None, scroller=None, scroller_hover=None, scrollbar_width=8.0, scroller_width=None, margin=0.0, on_scroll=None, ) ``` Makes its content scrollable. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `direction` | `"vertical"` | `"vertical"`, `"horizontal"` or `"both"`. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `padding` | `None` | Inner padding: `8`, `(vertical, horizontal)` or `(top, right, bottom, left)`. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `anchor_bottom` | `False` | Keeps the scroll pinned to the end (logs, terminals, chats). | | `rail` | `None` | Scrollbar rail color. | | `scroller` | `None` | Scroller color. | | `scroller_hover` | `None` | Scroller color on hover. | | `scrollbar_width` | `8.0` | Scrollbar width. | | `scroller_width` | `None` | Scroller width (defaults to the scrollbar's). | | `margin` | `0.0` | Margin between the scrollbar and the content. | Events: `on_scroll` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#scrollable) #### Related - [Column](https://albakore.github.io/pyzed/library/column/): Stacks children vertically. - [List item](https://albakore.github.io/pyzed/library/list-item/): A list row with icon, text and an end slot. ### Search input > An input with a magnifying glass, for filtering. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/search-input/ :::tip[In plain words] A text box with a magnifying glass, for typing what you are looking for. ::: An `input` with a magnifying glass icon and `"Search…"` as placeholder. It accepts every other parameter of [`ui.input`](https://albakore.github.io/pyzed/library/input/). `ui.search_input` · Category: [Forms](https://albakore.github.io/pyzed/library/#forms) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#search_input) **Code:** ```python pz.column([ ui.search_input("", on_query), ui.search_input("button", on_query, placeholder="Search components…"), ], spacing=10, width=360) ``` #### When to use - At the top of a list, tree or table to filter it as you type. - Pair it with `ui.fuzzy_filter` to rank the best matches first. #### Usage ```python import pyzed as pz from pyzed import ui class Finder(pz.App): def __init__(self): self.query = "" self.files = ["main.py", "app.py", "theme.py"] def view(self): matches = ui.fuzzy_filter(self.query, self.files) return pz.column([ ui.search_input(self.query, lambda q: setattr(self, "query", q)), *[ui.list_item(name, icon="file") for name, _ in matches], ], spacing=6) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python ui.search_input("", on_query, width=260) ``` ```python ui.search_input("button", on_query, width=260) ``` ```python ui.search_input("", on_query, placeholder="Search components…", width=260) ``` ##### Size ```python ui.search_input("", on_query, size="sm", width=260) ``` ```python ui.search_input("", on_query, size="lg", width=260) ``` ```python ui.search_input("", on_query, borderless=True, width=260) ``` #### Events Search input has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_input` | `(text)` | Callable that receives the new text on every keystroke. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Finder(pz.App): def __init__(self): self.query = "" self.files = ["main.py", "app.py", "theme.py"] def search(self, text): # on_input: every keystroke self.query = text def view(self): matches = ui.fuzzy_filter(self.query, self.files) return pz.column([ui.search_input(self.query, self.search), *[ui.list_item(name, icon="file") for name, _ in matches]], spacing=6) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Search: query: str class Finder(pz.App): query = "" files = ["main.py", "app.py", "theme.py"] def update(self, message): match message: case Search(query): self.query = query def view(self): matches = ui.fuzzy_filter(self.query, self.files) return pz.column([ui.search_input(self.query, Search), *[ui.list_item(name, icon="file") for name, _ in matches]], spacing=6) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: query: str = "" files: tuple = ("main.py", "app.py", "theme.py") def view(state, set_state): matches = ui.fuzzy_filter(state.query, list(state.files)) return pz.column([ui.search_input(state.query, lambda q: set_state(query=q)), *[ui.list_item(name, icon="file") for name, _ in matches]], spacing=6) ``` #### Properties and API ##### `ui.search_input` ```python search_input(value, on_input=None, *, placeholder='Search…', **kwargs) ``` An `input` with a magnifying glass icon. | Property | Default | Description | | --- | --- | --- | | `value` | *required* | Current text. | | `placeholder` | `"Search…"` | Hint text shown when empty. | | `**kwargs` | — | Same as `input`. | Events: `on_input` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#search_input) #### Related - [Input](https://albakore.github.io/pyzed/library/input/): A controlled text field with icon, placeholder and password mode. - [Picker](https://albakore.github.io/pyzed/library/picker/): A searchable list on a floating surface, with fuzzy matching. - [Command palette](https://albakore.github.io/pyzed/library/command-palette/): A command palette with fuzzy search and shortcuts. ### Segmented > A group of mutually exclusive text buttons. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/segmented/ :::tip[In plain words] A row of joined buttons where exactly one is chosen, like Day / Week / Month in a calendar. ::: A row of joined buttons where one is selected. `on_select` receives the chosen option. `ui.segmented` · Category: [Forms](https://albakore.github.io/pyzed/library/#forms) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#segmented) **Code:** ```python pz.column([ ui.segmented(["Editor", "Terminal", "Both"], "Editor", on_select), ui.segmented(["Day", "Week", "Month"], "Week", on_select), ], spacing=14, align="center") ``` #### When to use - To switch between two to five views or modes (Day / Week / Month). - For icons only, use a [Toggle group](https://albakore.github.io/pyzed/library/toggle-group/). #### Usage ```python import pyzed as pz from pyzed import ui class Calendar(pz.App): def __init__(self): self.mode = "Week" def view(self): return ui.segmented(["Day", "Week", "Month"], self.mode, lambda m: setattr(self, "mode", m)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python ui.segmented(["Code", "Preview"], "Code", on_select) ``` ```python ui.segmented(["Day", "Week", "Month"], "Week", on_select) ``` ```python ui.segmented(["XS", "S", "M", "L", "XL"], "M", on_select) ``` ##### Selection ```python ui.segmented(["Editor", "Terminal", "Both"], "Editor", on_select) ``` ```python ui.segmented(["Editor", "Terminal", "Both"], "Both", on_select) ``` ##### States and events ```python ui.segmented([("list", "List", "list"), ("grid", "Grid", "layout-grid")], "grid", on_select) ``` ```python ui.segmented(["Day", "Week", "Month"], "Week", on_select, width=320) ``` ```python ui.segmented(["Day", "Week", "Month"], "Day", on_select, disabled={"Month"}) ``` ```python ui.segmented(["Code", "Preview"], "Code", on_select, size="sm") ``` #### Events Segmented has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_select` | `(item)` | Callable that receives the chosen item. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Calendar(pz.App): def __init__(self): self.mode = "Week" def view(self): return pz.column([ ui.segmented(["Day", "Week", "Month"], self.mode, lambda m: setattr(self, "mode", m)), ui.label(f"Showing a {self.mode.lower()}"), ], spacing=8, align="center") ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Mode: name: str class Calendar(pz.App): mode = "Week" def update(self, message): match message: case Mode(name): self.mode = name def view(self): return ui.segmented(["Day", "Week", "Month"], self.mode, Mode) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: mode: str = "Week" def view(state, set_state): return ui.segmented(["Day", "Week", "Month"], state.mode, lambda m: set_state(mode=m)) ``` #### Tips :::tip Once clicked or reached with Tab it has the keyboard focus: ←/→ pick the previous or next option (skipping disabled ones) and Home/End the first and last. ::: #### Properties and API ##### `ui.segmented` ```python segmented( options, selected, on_select=None, *, size='md', width=None, disabled=False, id=None, theme=None, ) ``` A group of mutually exclusive buttons. | Property | Default | Description | | --- | --- | --- | | `options` | *required* | Strings, `(value, label)` or `(value, label, icon)`. | | `selected` | *required* | The active value. | | `size` | `"md"` | `"sm"`, `"md"` or `"lg"`. | | `width` | `None` | `"fill"` stretches the buttons evenly. | | `disabled` | `False` | `True`, or the values to disable. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_select` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#segmented) #### Related - [Toggle group](https://albakore.github.io/pyzed/library/toggle-group/): An icon-only segmented control. - [Radio group](https://albakore.github.io/pyzed/library/radio-group/): Mutually exclusive options as radio buttons. - [Tab bar](https://albakore.github.io/pyzed/library/tab-bar/): Editor tabs with icons, dirty dots and close buttons. ### Select > A dropdown to choose one option. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/select/ :::tip[In plain words] A box that opens a list so you can pick one option from it. ::: A dropdown in the theme style. Options are shown with `str()`, so strings, enums or dataclasses all work, and `on_select` receives the chosen object. `ui.select` · Category: [Forms](https://albakore.github.io/pyzed/library/#forms) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#select) **Code:** ```python pz.row([ ui.select(["Python", "Rust", "TypeScript"], "Rust", on_select, width=180), ui.select(["UTF-8", "Latin-1"], None, on_select, placeholder="Encoding…", width=180), ], spacing=12) ``` #### When to use - To pick one of many options when there is no room to show them all (language, theme, encoding). - With two to five short options, [Segmented](https://albakore.github.io/pyzed/library/segmented/) or a [Radio group](https://albakore.github.io/pyzed/library/radio-group/) shows them at a glance. #### Usage ```python import pyzed as pz from pyzed import ui class Settings(pz.App): def __init__(self): self.language = "Python" def view(self): return ui.select(["Python", "Rust", "TypeScript"], self.language, lambda value: setattr(self, "language", value), width=180) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### State ```python ui.select(["Python", "Rust", "TypeScript"], "Rust", on_select, width=200) ``` ```python ui.select(["UTF-8", "Latin-1"], None, on_select, placeholder="Encoding…", width=200) ``` ```python ui.select(["One Dark"], "One Dark", width=200) ``` ##### Size ```python ui.select(["Python", "Rust"], "Python", on_select, size="sm", width=200) ``` ```python ui.select(["Python", "Rust"], "Python", on_select, size="md", width=200) ``` ```python ui.select(["Python", "Rust"], "Python", on_select, size="lg", width=200) ``` ##### States and events `on_open` and `on_close` run when the menu opens and closes. ```python ui.select(["One Dark"], "One Dark", on_select, disabled=True, width=200) ``` ```python ui.select(["UTF-8", "Latin-1"], None, on_select, placeholder="Encoding…", invalid=True, width=200) ``` ##### Base widget The `pz.*` widget underneath: no theme, every color and size is yours. ```python pz.pick_list(["Small", "Medium", "Large"], "Medium", on_select, width=200, bg="#2b2140", color="#e9d5ff", border_color="#c678dd", radius=8) ``` #### Events Select has **3 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_select` | `ui.select`, `pz.pick_list` | `(item)` | Callable that receives the chosen item. | | `on_open` | `ui.select`, `pz.pick_list` | `()` | Sent when the menu opens. | | `on_close` | `ui.select`, `pz.pick_list` | `()` | Sent when the menu closes. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Settings(pz.App): def __init__(self): self.language = "Python" self.open = False def view(self): return pz.column([ ui.select(["Python", "Rust", "TypeScript"], self.language, lambda value: setattr(self, "language", value), # on_select: the option on_open=lambda: setattr(self, "open", True), on_close=lambda: setattr(self, "open", False), width=180), ui.muted("Choosing…" if self.open else f"Language: {self.language}"), ], spacing=8) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Language: name: str class Settings(pz.App): language = "Python" def update(self, message): match message: case Language(name): self.language = name def view(self): return ui.select(["Python", "Rust", "TypeScript"], self.language, Language, width=180) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: language: str = "Python" def view(state, set_state): return ui.select(["Python", "Rust", "TypeScript"], state.language, lambda value: set_state(language=value), width=180) ``` #### Tips :::tip It takes the keyboard focus like a text field (a click or Tab) and keeps it after you pick an option: then ↓/↑ choose the next or previous option without opening the menu, Home/End the first and last, and typing jumps to the option that starts with those letters. Enter, Space, Alt+↓ or F4 open the menu; there ↑/↓ move, Enter picks and Esc closes. Pass `id=` to focus it with `pz.Command.focus(id)`. ::: #### Properties and API ##### `ui.select` ```python select( options, selected=None, on_select=None, *, placeholder='Select…', width=None, size='md', disabled=False, invalid=False, on_open=None, on_close=None, id=None, theme=None, ) ``` A dropdown with the theme style. Options are displayed with `str()`, so strings, enums, dataclasses or database models all work; `on_select` receives the chosen object, not its label. | Property | Default | Description | | --- | --- | --- | | `options` | *required* | List of options. | | `selected` | `None` | Current option. | | `placeholder` | `"Select…"` | Hint text shown when empty. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `size` | `"md"` | `"sm"`, `"md"` or `"lg"`. | | `disabled` | `False` | Greys it out. | | `invalid` | `False` | Paints the border in the error color. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_select`, `on_open`, `on_close` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#select) ##### `pz.pick_list` ```python pick_list( options, selected=None, on_select=None, *, on_open=None, on_close=None, placeholder=None, width=None, padding=None, text_size=None, font=None, handle=None, handle_size=12.0, menu_height=None, bg=None, color=None, placeholder_color=None, handle_color=None, border_color=None, hover_border_color=None, radius=None, menu_bg=None, menu_color=None, menu_border_color=None, selected_bg=None, selected_color=None, focus_border_color=None, id=None, ) ``` A dropdown to choose one of `options`. `on_select(option)` receives the chosen one. For the themed dropdown use `ui.select`. It takes the keyboard focus like a text field (a click, Tab or `Command.focus(id)`) and keeps it after a choice: ↑/↓ then pick the previous or next option without opening it, Home/End the first and last and typing jumps to an option; Enter, Space, Alt+↓ or F4 open the menu, where ↑/↓ move, Enter picks and Esc closes. | Property | Default | Description | | --- | --- | --- | | `options` | *required* | List of options. | | `selected` | `None` | Current option. | | `placeholder` | `None` | Hint text shown when empty. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `padding` | `None` | Inner padding: `8`, `(vertical, horizontal)` or `(top, right, bottom, left)`. | | `text_size` | `None` | Text size. | | `font` | `None` | Font family. | | `handle` | `None` | Arrow icon character. | | `handle_size` | `12.0` | Arrow size. | | `menu_height` | `None` | Maximum menu height. | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `color` | `None` | Text or icon color. | | `placeholder_color` | `None` | Placeholder color. | | `handle_color` | `None` | Arrow color. | | `border_color` | `None` | Border color. | | `hover_border_color` | `None` | Border color on hover. | | `radius` | `None` | Corner radius: a number or `(top_left, top_right, bottom_right, bottom_left)`. | | `menu_bg` | `None` | Menu background. | | `menu_color` | `None` | Menu text. | | `menu_border_color` | `None` | Menu border. | | `selected_bg` | `None` | Background of the highlighted option. | | `selected_color` | `None` | Text of the highlighted option. | | `focus_border_color` | `None` | Border color while it has the keyboard focus. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | Events: `on_select`, `on_open`, `on_close` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#pick_list) #### Related - [Segmented](https://albakore.github.io/pyzed/library/segmented/): A group of mutually exclusive text buttons. - [Radio group](https://albakore.github.io/pyzed/library/radio-group/): Mutually exclusive options as radio buttons. - [Picker](https://albakore.github.io/pyzed/library/picker/): A searchable list on a floating surface, with fuzzy matching. ### Service row > A settings row for an MCP server, agent or skill: status, switch and menu. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/service-row/ :::tip[In plain words] One line of a settings page for a tool the assistant uses: whether it works, a switch to turn it on or off, and a menu with more options. ::: `ui.ServiceRow` is a component for one thing an AI agent uses (an MCP server, an external agent, a skill) on a settings page: an icon, the name with its `version` and a status dot, the `detail` (its command or URL, in a monospace font) and a `summary`; then a spinner while `busy`, a main button (`primary`, such as Update or Install), an on/off switch (`enabled`; `None` hides it) and a `⋯` menu with the `actions` (`ui.MenuItem`). `status` colors the dot: `running` and `installed` green, `starting` yellow, `update` in the accent color, `error` red, `off` and `missing` gray. `status_text` is the dot's tooltip, and it shows under the name for `error`, `missing` and `update`. `ui.ServiceRow` · Category: [AI agents](https://albakore.github.io/pyzed/library/#ai-agents) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#servicerow) **Code:** ```python pz.column([ ui.ServiceRow(name="github", detail="npx -y @modelcontextprotocol/server-github", icon_name="github", status="running", enabled=True, on_toggle=on_toggle, actions=[ui.MenuItem("Edit", on_edit, icon="pencil")]), ui.ServiceRow(name="filesystem", detail="uvx mcp-server-filesystem ~/notes", status="error", status_text="Exited with code 1", enabled=True, on_toggle=on_toggle), ui.ServiceRow(name="Gemini CLI", version="0.64.0", icon_name="bot", status="update", status_text="0.65.0 is available", primary="Update", on_primary=on_update), ], spacing=4, width=560) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - In the settings of an app with AI agents: one row per MCP server, agent or skill. - For any list of services that can be turned on and off, updated or removed. #### Usage ```python import pyzed as pz from pyzed import ui class Settings(pz.App): def __init__(self): self.on = True def view(self): return ui.ServiceRow(name="github", detail="npx -y @modelcontextprotocol/server-github", status="running" if self.on else "off", enabled=self.on, on_toggle=lambda e: setattr(self, "on", e.value), actions=[ui.MenuItem("Remove", self.remove, icon="trash-2", danger=True)]) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### State `enabled=False` also dims the name and the icon. ```python pz.container(ui.ServiceRow(name="github", detail="npx -y server-github", status="running", enabled=True), width=420) ``` ```python pz.container(ui.ServiceRow(name="github", detail="npx -y server-github", status="starting", enabled=True), width=420) ``` ```python pz.container(ui.ServiceRow(name="github", detail="npx -y server-github", status="error", status_text="Exited with code 1", enabled=True), width=420) ``` ```python pz.container(ui.ServiceRow(name="github", detail="npx -y server-github", status="off", enabled=False), width=420) ``` ```python pz.container(ui.ServiceRow(name="Gemini CLI", version="0.64.0", icon_name="bot", status="installed"), width=420) ``` ```python pz.container(ui.ServiceRow(name="Codex CLI", icon_name="bot", status="missing", status_text="Not installed yet", primary="Install"), width=420) ``` ```python pz.container(ui.ServiceRow(name="Gemini CLI", version="0.64.0", icon_name="bot", status="update", status_text="0.65.0 is available", primary="Update"), width=420) ``` ##### Options The `⋯` menu is drawn open, as after a click on it. ```python pz.container(ui.ServiceRow(name="notes", icon_name="book-open", status="running", summary="Reads and writes the notes folder."), width=420) ``` ```python pz.container(ui.ServiceRow(name="Gemini CLI", version="0.64.0", icon_name="bot", busy=True, primary="Update"), width=420) ``` ```python pz.container(ui.ServiceRow(name="github", detail="npx -y server-github", status="running", enabled=True, actions=[ui.MenuItem("Edit", on_edit, icon="pencil"), ui.MenuItem("Remove", on_remove, icon="trash-2", danger=True)]), width=420) ``` #### Events Service row has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Handler gets | When | | --- | --- | --- | | `on_toggle` | `(event)` | The switch was flipped. | | `on_primary` | `(event)` | The main button was pressed. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Settings(pz.App): def __init__(self): self.on = True self.updates = 0 def view(self): return ui.ServiceRow(name="github", status="running" if self.on else "off", enabled=self.on, primary="Update", on_toggle=lambda e: setattr(self, "on", e.value), # the switch on_primary=lambda e: setattr(self, "updates", self.updates + 1)) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Enable: on: bool class Settings(pz.App): on = True def update(self, message): match message: case Enable(on): self.on = on def view(self): return ui.ServiceRow(name="github", enabled=self.on, status="running" if self.on else "off", on_toggle=lambda e: Enable(e.value)) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: on: bool = True def view(state, set_state): return ui.ServiceRow(name="github", enabled=state.on, status="running" if state.on else "off", on_toggle=lambda e: set_state(on=e.value)) ``` #### Properties and API ##### `ui.ServiceRow` ```python class ServiceRow ``` A component for one thing an agent uses (an MCP server, an external agent, a skill), like the rows of Zed's agent settings: a status dot, the name and command, an on/off switch, a main button and a `⋯` menu. | Property | Default | Description | | --- | --- | --- | | `name` | `""` | Name. | | `detail` | `""` | The command or URL, in a monospace font. | | `summary` | `""` | A line about it. | | `icon_name` | `"plug"` | The icon. | | `status` | `""` | `running`, `starting`, `error`, `off`, `installed`, `missing` or `update` (the dot's color). | | `status_text` | `""` | The dot's tooltip; shown under the name for errors and updates. | | `version` | `""` | A version or a source. | | `enabled` | `None` | The switch (`None` hides it). | | `busy` | `False` | Shows a spinner. | | `primary` | `""` | Text of the main button (Update, Install…). | | `actions` | `None` | `ui.MenuItem` entries of the `⋯` menu. | | `theme` | `None` | Theme. | Events: `on_toggle`, `on_primary` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#servicerow) #### Related - [Catalog](https://albakore.github.io/pyzed/library/catalog/): Things to install, with a search box and Install or Update. - [Switch](https://albakore.github.io/pyzed/library/switch/): An on/off switch for settings that apply at once. - [Menu](https://albakore.github.io/pyzed/library/menu/): A context menu with icons, shortcuts and checks. - [Settings group](https://albakore.github.io/pyzed/library/settings-group/): A titled block of field rows, for settings screens. ### Settings group > A titled block of field rows, for settings screens. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/settings-group/ :::tip[In plain words] A titled block of settings, like a section of a preferences window. ::: A titled block of `ui.field` rows separated by lines, with an optional description, like a settings screen. `ui.settings_group` · Category: [Data](https://albakore.github.io/pyzed/library/#data) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#settings_group) **Code:** ```python pz.container(ui.settings_group("Editor", [ ui.field("Font size", ui.number_field(14, on_change, suffix="px")), ui.field("Soft wrap", ui.switch(True, on_toggle)), ui.field("Theme", ui.select(["One Dark", "One Light"], "One Dark", on_select, width=150)), ], description="Editor preferences."), width=460) ``` #### When to use - To organize a preferences screen into sections (Editor, Files, Git…). #### Usage ```python import pyzed as pz from pyzed import ui pz.container(ui.settings_group("Editor", [ ui.field("Font size", ui.number_field(14, on_change, suffix="px")), ui.field("Soft wrap", ui.switch(True, on_toggle)), ui.field("Theme", ui.select(["One Dark", "One Light"], "One Dark", on_select, width=150)), ], description="Editor preferences."), width=460) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python pz.container(ui.settings_group("Files", [ ui.field("Autosave", ui.switch(True, on_toggle)), ui.field("Trim whitespace", ui.checkbox(False, on_toggle)), ]), width=380) ``` ```python pz.container(ui.settings_group("Git", [ ui.field("Inline blame", ui.switch(False, on_toggle)), ], description="Shown in the editor gutter."), width=380) ``` ##### States and events ```python pz.container(ui.settings_group("Editor", [ui.field("Wrap lines", ui.switch(True, on_toggle))], end=ui.button("Reset", on_press, size="sm", variant="ghost")), width=420) ``` #### Events Settings group has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.settings_group` ```python settings_group(title, rows, *, description=None, end=None, theme=None) ``` A titled block of `ui.field` rows separated by lines, like a settings screen. | Property | Default | Description | | --- | --- | --- | | `title` | *required* | Group title. | | `rows` | *required* | The rows (usually `ui.field`). | | `description` | `None` | Secondary text. | | `end` | `None` | Widget at the right of the title (a Reset button…). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#settings_group) #### Related - [Field](https://albakore.github.io/pyzed/library/field/): A settings row: title and description left, control right. - [Accordion](https://albakore.github.io/pyzed/library/accordion/): Stacked collapsible sections, like the panels of a settings screen. - [Card](https://albakore.github.io/pyzed/library/card/): A bordered surface with an optional title and actions. ### Shader > A widget painted on the GPU by your own WGSL code. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/shader/ :::tip[In plain words] A surface painted by the graphics card, for moving backgrounds and visual effects. ::: `pz.shader` runs a function you write in WGSL, `fn shade(uv, px, size, time) -> vec4`, for every pixel of the widget, every frame, on the GPU: animated backgrounds, plasma, fire or a radar sweep cost Python nothing. Each entry of `uniforms` becomes a WGSL function of the same name, and `mouse()` gives the pointer. Without a GPU the widget shows `fallback`. See the [Shaders guide](https://albakore.github.io/pyzed/shading/shaders/) and the [showcase](https://albakore.github.io/pyzed/showcase/). `pz.shader` · Category: [Content](https://albakore.github.io/pyzed/library/#content) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#shader) **Code:** ```python pz.shader(""" fn shade(uv: vec2, px: vec2, size: vec2, time: f32) -> vec4 { let wave = 0.5 + 0.5 * sin(uv.x * 12.0 + uv.y * 4.0 + time * speed()); return vec4(mix(vec3(0.08, 0.09, 0.2), tint().rgb, wave), 1.0); } """, uniforms={"speed": 2.0, "tint": "#c678dd"}, width=640, height=240, time=0.5, fallback=pz.Gradient(["#14172f", "#c678dd"], angle=0)) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For animated backgrounds behind glass panels, menus and HUDs. - For game visuals and effects that would be too slow to draw from Python every frame. #### Usage ```python import pyzed as pz pz.shader(""" fn shade(uv: vec2, px: vec2, size: vec2, time: f32) -> vec4 { let wave = 0.5 + 0.5 * sin(uv.x * 12.0 + uv.y * 4.0 + time * speed()); return vec4(mix(vec3(0.08, 0.09, 0.2), tint().rgb, wave), 1.0); } """, uniforms={"speed": 2.0, "tint": "#c678dd"}, width=640, height=240, time=0.5, fallback=pz.Gradient(["#14172f", "#c678dd"], angle=0)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Uniforms Each capture is one frame at `time=0.5`; run the example to see it move. Without a GPU the widget draws its `fallback`. ```python pz.shader(""" fn shade(uv: vec2, px: vec2, size: vec2, time: f32) -> vec4 { let wave = 0.5 + 0.5 * sin(uv.x * 12.0 + uv.y * 4.0 + time * 2.0); return vec4(mix(vec3(0.08, 0.09, 0.2), tint().rgb, wave), 1.0); } """, uniforms={"tint": "#c678dd"}, width=260, height=110, time=0.5, fallback=pz.Gradient(["#14172f", "#c678dd"], angle=0)) ``` ```python pz.shader(""" fn shade(uv: vec2, px: vec2, size: vec2, time: f32) -> vec4 { let wave = 0.5 + 0.5 * sin(uv.x * 12.0 + uv.y * 4.0 + time * 2.0); return vec4(mix(vec3(0.08, 0.09, 0.2), tint().rgb, wave), 1.0); } """, uniforms={"tint": "#56b6c2"}, width=260, height=110, time=0.5, fallback=pz.Gradient(["#14172f", "#56b6c2"], angle=0)) ``` ```python pz.shader(""" fn shade(uv: vec2, px: vec2, size: vec2, time: f32) -> vec4 { let wave = 0.5 + 0.5 * sin(uv.x * 12.0 + uv.y * 4.0 + time * 2.0); return vec4(mix(vec3(0.08, 0.09, 0.2), tint().rgb, wave), 1.0); } """, uniforms={"tint": "#e5c07b"}, width=260, height=110, time=0.5, fallback=pz.Gradient(["#14172f", "#e5c07b"], angle=0)) ``` #### Events Shader has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Tips :::tip Shaders need the GPU renderer. Always pass a `fallback` that looks right on its own: it is what the software renderer and machines without a GPU draw. ::: #### Properties and API ##### `pz.shader` ```python shader( code, *, uniforms=None, textures=None, width=None, height=None, animate=True, time=None, fallback=None, ) ``` A widget painted on the GPU by your WGSL `fn shade(uv, px, size, time) -> vec4`, which returns each pixel's color, or by a shader graph made of nodes (a `.pzshad` path or a [`pyzed.shading`](https://albakore.github.io/pyzed/reference/shading/) `Graph` or `Shader`). Each entry of `uniforms` becomes a function of the same name (`{"speed": 2}` -> `speed()`); `mouse()` gives the pointer. Without a GPU the widget shows `fallback`. Raises `ValueError` with the compiler's message for invalid code. See the [shaders](https://albakore.github.io/pyzed/shading/shaders/) guide. | Property | Default | Description | | --- | --- | --- | | `code` | *required* | WGSL source that defines `shade` (and any helper functions), or a `.pzshad` path, `Graph` or `Shader`. | | `uniforms` | `None` | Up to 32 named values: a number, 2 to 4 numbers or a color. With a `.pzshad`, the shader's mutable variables by name. | | `textures` | `None` | Up to 8 images, `{name: path}`: each becomes `name(uv)`, the image's color at `uv`. | | `width` | `None` | Width (`"fill"` by default). | | `height` | `None` | Height (`"fill"` by default). | | `animate` | `True` | Redraw every frame so `time` moves (`True`). | | `time` | `None` | A fixed `time` in seconds, for a still frame. | | `fallback` | `None` | Color or gradient shown without a GPU. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#shader) #### Related - [Effects](https://albakore.github.io/pyzed/library/effects/): Glow, bloom, glass and opacity as style properties. - [Canvas](https://albakore.github.io/pyzed/library/canvas/): 2D drawing with shapes, paths, text and mouse events. - [Animation](https://albakore.github.io/pyzed/library/animation/): Presets, keyframes and transitions for any widget. ### Shortcuts > A searchable list of key bindings, grouped. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/shortcuts/ :::tip[In plain words] A searchable list of all the keyboard shortcuts of an app. ::: A searchable, grouped list of key bindings for a Keyboard shortcuts dialog. `groups` are `(title, [(action, keys), ...])` pairs. `ui.shortcuts` · Category: [Code and tools](https://albakore.github.io/pyzed/library/#code-and-tools) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#shortcuts) **Code:** ```python pz.container(ui.shortcuts([ ("File", [("Save", "ctrl-s"), ("Open file", "ctrl-p")]), ("View", [("Command palette", "ctrl-shift-p"), ("Toggle left dock", "ctrl-b")]), ], on_query=on_query, height=240), width=420) ``` #### When to use - Inside a `ui.modal` opened from a Help menu or with Ctrl+K Ctrl+S. #### Usage ```python import pyzed as pz from pyzed import ui pz.container(ui.shortcuts([ ("File", [("Save", "ctrl-s"), ("Open file", "ctrl-p")]), ("View", [("Command palette", "ctrl-shift-p"), ("Toggle left dock", "ctrl-b")]), ], on_query=on_query, height=240), width=420) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python pz.container(ui.shortcuts([("File", [("Save", "ctrl-s"), ("Open", "ctrl-o")])], on_query=on_query, height=130), width=360) ``` ```python pz.container(ui.shortcuts([("View", [("Command palette", "ctrl-shift-p"), ("Zoom in", "ctrl-=")])], query="pal", on_query=on_query, height=110), width=360) ``` #### Events Shortcuts has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_query` | `(text)` | Adds a search box. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Help(pz.App): def __init__(self): self.query = "" def view(self): return ui.shortcuts([("File", [("Save", "ctrl-s"), ("Open file", "ctrl-p")])], query=self.query, on_query=lambda q: setattr(self, "query", q)) # adds search ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Search: query: str class Help(pz.App): query = "" def update(self, message): match message: case Search(query): self.query = query def view(self): return ui.shortcuts([("File", [("Save", "ctrl-s")])], query=self.query, on_query=Search) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: query: str = "" def view(state, set_state): return ui.shortcuts([("File", [("Save", "ctrl-s"), ("Open file", "ctrl-p")])], query=state.query, on_query=lambda q: set_state(query=q)) ``` #### Properties and API ##### `ui.shortcuts` ```python shortcuts(groups, *, query='', on_query=None, height=380, theme=None) ``` A searchable list of key bindings, grouped (for a Keyboard shortcuts dialog). | Property | Default | Description | | --- | --- | --- | | `groups` | *required* | `[(title, [(label, keys), ...]), ...]`, keys like `"ctrl-s"`. | | `query` | `""` | Filter text. | | `height` | `380` | Height of the list. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_query` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#shortcuts) #### Related - [Kbd](https://albakore.github.io/pyzed/library/kbd/): Keyboard shortcuts drawn as keys, with symbols on macOS. - [Keybinding hint](https://albakore.github.io/pyzed/library/keybinding-hint/): A muted “Open file Ctrl P” hint. - [About](https://albakore.github.io/pyzed/library/about/): An About box with icon, version, details and links. ### Sign-in prompt > Asks to sign in, then shows the browser step, a code and Cancel. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/auth-prompt/ :::tip[In plain words] A box that asks you to sign in, with a button for each way to do it. ::: `ui.AuthPrompt` is a component that asks to sign in, for an agent or a service that needs it. It shows a `title`, an optional `detail` and one button per way to sign in: `methods` are dicts with `id`, `name` and optional `description` (shown as a tooltip) and `icon`, and the first one is the main button. Picking one reports `on_pick` with its id. While `waiting` holds that id it shows a spinner and what is happening (`waiting_text`, or "Waiting for the browser…"), the `code` to type with a copy button when there is one, Open the page again when `url` is set, and Cancel. `error` shows a message in red. `ui.AuthPrompt` · Category: [AI agents](https://albakore.github.io/pyzed/library/#ai-agents) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#authprompt) **Code:** ```python pz.container(ui.AuthPrompt( title="Sign in to use the agent", detail="Your account is used to run the model.", methods=[{"id": "browser", "name": "Log in with the browser", "icon": "globe"}, {"id": "key", "name": "Use an API key", "icon": "key-round"}], on_pick=on_pick, ), width=440) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - Where an agent or a connected service needs the user to sign in before it can work. - For a device sign-in: show the `code` the user types on the page that opened. #### Usage ```python import pyzed as pz from pyzed import ui class Agent(pz.App): def __init__(self): self.waiting, self.code = "", "" def sign_in(self, method): self.waiting = method self.code = start_device_login() # opens the browser and returns the code to type def view(self): return ui.AuthPrompt(title="Sign in to use the agent", waiting=self.waiting, code=self.code, methods=[{"id": "browser", "name": "Log in with the browser"}], on_pick=lambda e: self.sign_in(e.value), on_cancel=lambda e: setattr(self, "waiting", ""), on_copy=lambda e: pz.Command.copy(e.value)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Ways to sign in The first method is the main (solid) button. ```python pz.container(ui.AuthPrompt(title="Sign in to continue", methods=[{"id": "browser", "name": "Log in with the browser"}]), width=380) ``` ```python pz.container(ui.AuthPrompt(title="Sign in to continue", methods=[ {"id": "browser", "name": "Log in with the browser", "icon": "globe"}, {"id": "key", "name": "Use an API key", "icon": "key-round"}, ]), width=380) ``` ```python pz.container(ui.AuthPrompt(title="Sign in to continue", detail="The agent needs your account.", methods=[{"id": "browser", "name": "Log in with the browser"}]), width=380) ``` ```python pz.container(ui.AuthPrompt(title="Sign in to continue", error="The sign-in was cancelled.", methods=[{"id": "browser", "name": "Try again"}]), width=380) ``` ##### Waiting ```python pz.container(ui.AuthPrompt(title="Sign in to continue", waiting="browser"), width=380) ``` ```python pz.container(ui.AuthPrompt(title="Sign in to continue", waiting="cli", waiting_text="Finish signing in in the terminal."), width=380) ``` ```python pz.container(ui.AuthPrompt(title="Sign in to continue", waiting="device", code="WDJB-MJHT", url="https://example.com/device"), width=380) ``` #### Events Sign-in prompt has **4 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Handler gets | When | | --- | --- | --- | | `on_pick` | `(event)` | A method was picked (`event.value` is its id). | | `on_cancel` | `(event)` | Cancel. | | `on_open_url` | `(event)` | Open the page again. | | `on_copy` | `(event)` | The code was copied. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Agent(pz.App): def __init__(self): self.waiting, self.code = "", "" def sign_in(self, method): # on_pick: event.value is the method's id self.waiting, self.code = method, "ABCD-1234" def view(self): return ui.AuthPrompt(title="Sign in to use the agent", waiting=self.waiting, code=self.code, methods=[{"id": "browser", "name": "Log in with the browser"}], on_pick=lambda e: self.sign_in(e.value), on_cancel=lambda e: setattr(self, "waiting", ""), on_copy=lambda e: pz.Command.copy(e.value)) # the code ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Picked: method: str class Agent(pz.App): waiting = "" def update(self, message): match message: case Picked(method): self.waiting = method case "cancel": self.waiting = "" def view(self): return ui.AuthPrompt(title="Sign in", waiting=self.waiting, methods=[{"id": "key", "name": "Use an API key"}], on_pick=lambda e: Picked(e.value), on_cancel="cancel") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: waiting: str = "" def view(state, set_state): return ui.AuthPrompt(title="Sign in", waiting=state.waiting, methods=[{"id": "browser", "name": "Log in with the browser"}], on_pick=lambda e: set_state(waiting=e.value), on_cancel=lambda e: set_state(waiting="")) ``` #### Tips :::tip The copy button only reports `on_copy` with the code in `event.value`; return `pz.Command.copy(e.value)` from it to put the code on the clipboard. ::: #### Properties and API ##### `ui.AuthPrompt` ```python class AuthPrompt ``` A component that asks to sign in, like Zed when an agent needs it: one button per way to sign in, then, while one runs, what is happening (the browser or a terminal is open), a code to type when there is one, Open the page again and Cancel. | Property | Default | Description | | --- | --- | --- | | `title` | `""` | The heading. | | `detail` | `""` | A line under it. | | `methods` | `None` | Dicts with `id`, `name`, optional `description` and `icon`; the first is the main one. | | `waiting` | `""` | The id of the method in progress (`""` when none). | | `waiting_text` | `""` | What to show while waiting. | | `code` | `""` | A code to type (device sign-in). | | `url` | `""` | The page that was opened. | | `error` | `""` | An error to show. | | `icon_name` | `"key-round"` | The icon. | | `theme` | `None` | Theme. | Events: `on_pick`, `on_cancel`, `on_open_url`, `on_copy` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#authprompt) #### Related - [Callout](https://albakore.github.io/pyzed/library/callout/): An inline notice with a title, text and actions. - [Button](https://albakore.github.io/pyzed/library/button/): The themed button: variants, sizes, icons and shortcuts. - [Service row](https://albakore.github.io/pyzed/library/service-row/): A settings row for an MCP server, agent or skill: status, switch and menu. ### Slider > Pick a number in a range by dragging. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/slider/ :::tip[In plain words] A bar with a knob you drag to pick an amount, like a volume control. ::: A themed slider between `min` and `max` (0 to 1 by default) that moves in `step` increments. `on_change` receives the new value while dragging. `ui.slider` · Category: [Forms](https://albakore.github.io/pyzed/library/#forms) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#slider) **Code:** ```python pz.column([ ui.slider(0.35, on_change), ui.slider(70, on_change, min=0, max=100, step=1), ], spacing=18, width=360) ``` #### When to use - For values where the exact number matters less than the feel: volume, opacity, zoom. - When users need to type an exact value, use a [Number field](https://albakore.github.io/pyzed/library/number-field/). #### Usage ```python import pyzed as pz from pyzed import ui class Player(pz.App): def __init__(self): self.volume = 70 def view(self): return pz.row([ ui.slider(self.volume, lambda v: setattr(self, "volume", v), min=0, max=100, step=1), ui.label(f"{self.volume:.0f}%"), ], spacing=12, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Value ```python ui.slider(0.0, on_change, width=240) ``` ```python ui.slider(0.35, on_change, width=240) ``` ```python ui.slider(1.0, on_change, width=240) ``` ##### Range and step ```python ui.slider(70, on_change, min=0, max=100, step=1, width=240) ``` ```python pz.column([ui.slider(40, on_change, min=0, max=100, step=10, width=240), ui.muted("40 %")], spacing=6, align="center") ``` ##### States and events `on_release` runs when the drag ends: save or apply there instead of on every move. ```python ui.slider(70, on_change, min=0, max=100, step=1, show_value=True, width=240) ``` ```python ui.slider(0.35, on_change, show_value="{:.0%}", width=240) ``` ```python ui.slider(6, on_change, min=0, max=10, step=1, vertical=True, height=110, show_value=True) ``` ```python ui.slider(0.6, on_change, disabled=True, width=240) ``` ##### Base widget The `pz.*` widget underneath: no theme, every color and size is yours. ```python pz.slider(0, 100, 60, on_change=on_change, width=240, accent="#e5c07b", knob_color="#ffffff") ``` ```python pz.vertical_slider(0, 100, 60, on_change=on_change, height=120, accent="#56b6c2") ``` #### Events Slider has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_change` | `ui.slider`, `pz.slider` | `(value)` | Callable that receives the new value. | | `on_release` | `ui.slider`, `pz.slider` | `()` | Sent when the drag ends (save or apply there). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Player(pz.App): def __init__(self): self.volume = 70 self.saved = 70 def view(self): return pz.row([ ui.slider(self.volume, lambda v: setattr(self, "volume", v), # on_change: while dragging min=0, max=100, step=1, on_release=lambda: setattr(self, "saved", self.volume)), # on_release: once ui.label(f"{self.volume:.0f}% (saved {self.saved:.0f}%)"), ], spacing=12, align="center", width=420) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Volume: value: float class Player(pz.App): volume = 70 saved = 70 def update(self, message): match message: case Volume(value): self.volume = value case "save": self.saved = self.volume def view(self): return ui.slider(self.volume, Volume, min=0, max=100, step=1, on_release="save") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: volume: float = 70 def view(state, set_state): return pz.row([ ui.slider(state.volume, lambda v: set_state(volume=v), min=0, max=100, step=1), ui.label(f"{state.volume:.0f}%"), ], spacing=12, align="center", width=420) ``` #### Tips :::tip Once clicked or reached with Tab it has the keyboard focus: the arrows move it one `step`, with Shift (or Page Up/Down) ten, and Home/End jump to `min`/`max`. ::: #### Properties and API ##### `ui.slider` ```python slider( value, on_change=None, *, min=0.0, max=1.0, step=0.01, on_release=None, vertical=False, width=None, height=None, disabled=False, show_value=False, id=None, theme=None, ) ``` A slider. | Property | Default | Description | | --- | --- | --- | | `value` | *required* | Current value. | | `min` | `0.0` | Minimum. | | `max` | `1.0` | Maximum. | | `step` | `0.01` | Step. | | `vertical` | `False` | Stands it up. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `disabled` | `False` | Greys it out. | | `show_value` | `False` | Shows the number next to it: `True`, or a format such as `"{:.0%}"`. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_change`, `on_release` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#slider) ##### `pz.slider` ```python slider( min, max, value, *, step=1.0, on_change=None, on_release=None, width=None, height=None, vertical=False, accent=None, bg=None, knob_color=None, border_color=None, ) ``` A slider between `min` and `max`. | Property | Default | Description | | --- | --- | --- | | `min` | *required* | Minimum. | | `max` | *required* | Maximum. | | `value` | *required* | Current value. | | `step` | `1.0` | Step. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `vertical` | `False` | Vertical orientation. | | `accent` | `None` | Accent color (active part). | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `knob_color` | `None` | Knob color. | | `border_color` | `None` | Border color. | Events: `on_change`, `on_release` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#slider) ##### `pz.vertical_slider` ```python vertical_slider(min, max, value, **kwargs) ``` A vertical slider (`slider(..., vertical=True)`). | Property | Default | Description | | --- | --- | --- | | `min` | *required* | Minimum. | | `max` | *required* | Maximum. | | `value` | *required* | Current value. | | `**kwargs` | — | Same as `slider`. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#vertical_slider) #### Related - [Number field](https://albakore.github.io/pyzed/library/number-field/): A number with −/+ buttons, limits, step and suffix. - [Progress](https://albakore.github.io/pyzed/library/progress/): A thin progress bar in a semantic color. ### Space > Fixed gaps and flexible spacers. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/spacing/ :::tip[In plain words] Empty space: a fixed gap, or a spring that pushes things apart. ::: `pz.space(width, height)` is an empty box of a given size. `pz.hspace()` and `pz.vspace()` are flexible gaps that take the free space, pushing their siblings to the edges of a row or column. `pz.space` · Category: [Layout](https://albakore.github.io/pyzed/library/#layout) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#space) **Code:** ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.column([ pz.row([box("left"), pz.hspace(), box("right")], width=440), pz.row([box("a"), pz.space(width=60), box("60 px later", w=140)]), ], spacing=16) ``` #### When to use - To push actions to the right of a toolbar, or a footer to the bottom of a panel. #### Usage ```python import pyzed as pz from pyzed import ui box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.column([ pz.row([box("left"), pz.hspace(), box("right")], width=440), pz.row([box("a"), pz.space(width=60), box("60 px later", w=140)]), ], spacing=16) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.row([box("left"), pz.hspace(), box("right")], width=320) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.row([box("a"), pz.space(width=60), box("b")]) ``` ```python box = lambda text, w=90, h=44: pz.container(ui.label(text), center=True, width=w, height=h, bg=pz.theme.current().element, radius=6) pz.column([box("top"), pz.vspace(), box("bottom")], height=150) ``` #### Events Space has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.space` ```python space(width=None, height=None) ``` Empty space of a given size. | Property | Default | Description | | --- | --- | --- | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#space) ##### `pz.hspace` ```python hspace(width='fill') ``` Flexible horizontal gap: pushes the siblings in a row towards the edges. | Property | Default | Description | | --- | --- | --- | | `width` | `"fill"` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#hspace) ##### `pz.vspace` ```python vspace(height='fill') ``` Flexible vertical gap: pushes the siblings in a column towards the edges. | Property | Default | Description | | --- | --- | --- | | `height` | `"fill"` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#vspace) #### Related - [Row](https://albakore.github.io/pyzed/library/row/): Lays out children horizontally. - [Column](https://albakore.github.io/pyzed/library/column/): Stacks children vertically. - [Divider](https://albakore.github.io/pyzed/library/divider/): A thin line in the theme's border color. ### Sparkline > A tiny line chart for trends. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/sparkline/ :::tip[In plain words] A tiny line chart that shows if something is going up or down. ::: A small line chart, filled below the line by default, that shows the shape of a series. `ui.sparkline` · Category: [Data](https://albakore.github.io/pyzed/library/#data) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#sparkline) **Code:** ```python pz.column([ ui.sparkline([1, 4, 2, 6, 3, 7, 5, 8], width=240, height=48), ui.sparkline([8, 6, 7, 4, 5, 3, 2, 1], width=240, height=48, tint="error", fill=False), ], spacing=16) ``` #### When to use - Inline next to a number or in a table cell, where the trend matters more than the values. #### Usage ```python import pyzed as pz from pyzed import ui pz.column([ ui.sparkline([1, 4, 2, 6, 3, 7, 5, 8], width=240, height=48), ui.sparkline([8, 6, 7, 4, 5, 3, 2, 1], width=240, height=48, tint="error", fill=False), ], spacing=16) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python ui.sparkline([1, 4, 2, 6, 3, 7, 5, 8], width=200, height=40) ``` ```python ui.sparkline([1, 4, 2, 6, 3, 7, 5, 8], width=200, height=40, fill=False) ``` ```python ui.sparkline([8, 6, 7, 4, 5, 3, 2, 1], width=200, height=40, tint="error") ``` ```python ui.sparkline([2, 3, 3, 5, 6, 8, 9, 12], width=200, height=40, tint="success") ``` ##### Size ```python ui.sparkline([3, 5, 2, 6, 4, 7], width=80, height=20) ``` ```python ui.sparkline([3, 5, 2, 6, 4, 7, 5, 9, 6, 8], width=280, height=64) ``` #### Events Sparkline has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.sparkline` ```python sparkline(values, *, width=120, height=32, tint='accent', fill=True, theme=None) ``` A tiny line chart for trends. | Property | Default | Description | | --- | --- | --- | | `values` | *required* | Values. | | `width` | `120` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `32` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `tint` | `"accent"` | Semantic color: `"accent"`, `"error"`, `"warning"`, `"success"`, `"info"` or a token. | | `fill` | `True` | Fills the area under the line. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#sparkline) #### Related - [Stat](https://albakore.github.io/pyzed/library/stat/): A dashboard number with change and sparkline. - [Bar chart](https://albakore.github.io/pyzed/library/bar-chart/): A vertical bar chart with labels. ### Spinner > A spinning arc for loading states. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/spinner/ :::tip[In plain words] A spinning circle that says “wait, I'm working on it”. ::: A spinning arc. Its angle comes from the app clock, so keep a subscription such as `pz.every(1 / 30, ...)` active while it is shown or it will not move. `ui.spinner` · Category: [Feedback](https://albakore.github.io/pyzed/library/#feedback) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#spinner) **Code:** ```python pz.row([ ui.spinner(), ui.spinner(size=24, tint="success"), pz.row([ui.spinner(size=14), ui.muted("Indexing project…")], spacing=8, align="center"), ], spacing=24, align="center") ``` #### When to use - For short waits with an unknown duration: connecting, searching, loading a file. - For long work with known progress use [Progress](https://albakore.github.io/pyzed/library/progress/). #### Usage ```python import pyzed as pz from pyzed import ui class Loader(pz.App): def __init__(self): self.loading = True def subscription(self): return pz.every(1 / 30, lambda: None) if self.loading else None def view(self): return ui.spinner() if self.loading else ui.label("Done") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Size ```python ui.spinner(size=12) ``` ```python ui.spinner() ``` ```python ui.spinner(size=24) ``` ```python ui.spinner(size=36) ``` ##### Tint ```python ui.spinner(size=24, tint="success") ``` ```python ui.spinner(size=24, tint="warning") ``` ```python ui.spinner(size=24, tint="text_muted") ``` ##### With text ```python pz.row([ui.spinner(size=14), ui.muted("Indexing project…")], spacing=8, align="center") ``` ```python ui.button(pz.row([ui.spinner(size=12, tint="text"), pz.text("Saving")], spacing=6, align="center")) ``` #### Events Spinner has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.spinner` ```python spinner(*, size=16, tint='accent', speed=1.0, theme=None) ``` A spinning arc for loading states. Its angle comes from the clock, so keep a `pz.every(1/30, ...)` subscription active while it is shown. | Property | Default | Description | | --- | --- | --- | | `size` | `16` | Size. | | `tint` | `"accent"` | Semantic color: `"accent"`, `"error"`, `"warning"`, `"success"`, `"info"` or a token. | | `speed` | `1.0` | Turns per second. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#spinner) #### Related - [Progress](https://albakore.github.io/pyzed/library/progress/): A thin progress bar in a semantic color. - [Empty state](https://albakore.github.io/pyzed/library/empty-state/): A centered placeholder for empty lists and searches. ### Split > Two panes with a draggable divider. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/split/ :::tip[In plain words] Two areas side by side (or one above the other) with a line you drag to resize them. ::: Separates two widgets with a draggable divider in the theme's border color (accent while dragging). The `ratio` is yours: store it in `on_resize(ratio)`. `vertical=True` stacks the panes. `pz.split` is the base version with configurable `color`, `hover_color`, `thickness` and `handle`. `ui.split` · Category: [Workspace](https://albakore.github.io/pyzed/library/#workspace) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#split) **Code:** ```python t = pz.theme.current() pane = lambda title, bg: pz.container(ui.label(title), padding=12, width="fill", height="fill", bg=bg) ui.split(pane("Left", t.panel), ui.split(pane("Top", t.editor), pane("Bottom", t.background), vertical=True), ratio=0.4, on_resize=on_resize) ``` #### When to use - For side-by-side editors, a preview next to its source, or an editor above a terminal. - For one resizable side panel, [Resizable](https://albakore.github.io/pyzed/library/resizable/) is simpler. #### Usage ```python import pyzed as pz from pyzed import ui class Panes(pz.App): def __init__(self): self.ratio = 0.3 def view(self): return ui.split(self.sidebar(), self.editor(), ratio=self.ratio, on_resize=lambda r: setattr(self, "ratio", r)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Direction ```python t = pz.theme.current() ui.split(pz.container(ui.label("A"), padding=10, width="fill", height="fill", bg=t.panel), pz.container(ui.label("B"), padding=10, width="fill", height="fill"), on_resize=on_resize) ``` ```python t = pz.theme.current() ui.split(pz.container(ui.label("Top"), padding=10, width="fill", height="fill", bg=t.panel), pz.container(ui.label("Bottom"), padding=10, width="fill", height="fill"), vertical=True) ``` ```python t = pz.theme.current() ui.split(pz.container(ui.label("25%"), padding=10, width="fill", height="fill", bg=t.panel), pz.container(ui.label("75%"), padding=10, width="fill", height="fill"), ratio=0.25) ``` #### Events Split has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_resize` | `ui.split`, `pz.split` | `(ratio)` | Callable that receives the new ratio. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Panes(pz.App): def __init__(self): self.ratio = 0.3 def view(self): return ui.split(ui.muted(f"Sidebar ({self.ratio:.0%})"), main_view(), ratio=self.ratio, on_resize=lambda r: setattr(self, "ratio", r)) # the share of the first pane ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Ratio: value: float class Panes(pz.App): ratio = 0.3 def update(self, message): match message: case Ratio(value): self.ratio = value def view(self): return ui.split(ui.muted("Sidebar"), main_view(), ratio=self.ratio, on_resize=Ratio) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: ratio: float = 0.3 def view(state, set_state): return ui.split(ui.muted("Sidebar"), main_view(), ratio=state.ratio, on_resize=lambda r: set_state(ratio=r)) ``` #### Properties and API ##### `ui.split` ```python split( first, second, *, ratio=0.5, on_resize=None, vertical=False, min_size=80, theme=None, **kwargs, ) ``` `pz.split` with the divider in the theme's border color (accent while dragging). | Property | Default | Description | | --- | --- | --- | | `first` | *required* | First pane. | | `second` | *required* | Second pane. | | `ratio` | `0.5` | Proportion of the first pane (0–1). | | `vertical` | `False` | Vertical orientation. | | `min_size` | `80` | Minimum size of each pane. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | | `**kwargs` | — | Same as `pz.split`. | Events: `on_resize` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#split) ##### `pz.split` ```python split( first, second, *, ratio=0.5, on_resize=None, vertical=False, min_size=80.0, min_size_second=None, color=None, hover_color=None, thickness=1.0, handle=8.0, width=None, height=None, ) ``` Two panes with a draggable divider. For the theme style use `ui.split`. | Property | Default | Description | | --- | --- | --- | | `first` | *required* | First pane. | | `second` | *required* | Second pane. | | `ratio` | `0.5` | Proportion of the first pane (0–1). The split keeps the ratio the user drags to until this changes. | | `vertical` | `False` | Stacks the panes top/bottom. | | `min_size` | `80.0` | Minimum size of the first pane. | | `min_size_second` | `None` | Minimum size of the second pane. | | `color` | `None` | Divider color. | | `hover_color` | `None` | Divider color on hover or while dragging. | | `thickness` | `1.0` | Line thickness. | | `handle` | `8.0` | Width of the draggable area. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | Events: `on_resize` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#split) #### Related - [Resizable](https://albakore.github.io/pyzed/library/resizable/): A panel whose edge can be dragged to resize it. - [Panel](https://albakore.github.io/pyzed/library/panel/): A dockable, resizable side panel. - [Workspace](https://albakore.github.io/pyzed/library/workspace/): The layout of an editor-style window: title bar, docks, center, status bar. ### Split button > A main action plus an arrow that opens more options. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/split-button/ :::tip[In plain words] A button with two parts: the big part does the usual thing, the little arrow shows other ways to do it. ::: A button with a separate chevron on the right. `on_press` runs the main action and `on_menu` usually opens a `ui.menu` inside a `ui.popover` with the alternatives. `ui.split_button` · Category: [Actions](https://albakore.github.io/pyzed/library/#actions) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#split_button) **Code:** ```python pz.row([ ui.split_button("Run", on_run, on_menu, icon="play"), ui.split_button("Deploy", on_deploy, on_menu, variant="solid"), ], spacing=12) ``` #### When to use - When one action is the usual one but there are a few variations (Run / Run with arguments). - Avoid it when the options are equally important: use a [Select](https://albakore.github.io/pyzed/library/select/). #### Usage ```python import pyzed as pz from pyzed import ui class Runner(pz.App): def __init__(self): self.menu_open = False def view(self): button = ui.split_button("Run", self.run, lambda: setattr(self, "menu_open", True), icon="play") menu = ui.menu([ui.MenuItem("Run with arguments…", self.run_args), ui.MenuItem("Debug", self.debug, icon="bug")]) if self.menu_open else None return ui.popover(button, menu, y=32, on_dismiss=lambda: setattr(self, "menu_open", False)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Variant ```python ui.split_button("Run", on_run, on_menu, icon="play") ``` ```python ui.split_button("Run", on_run, on_menu, icon="play", variant="ghost") ``` ```python ui.split_button("Run", on_run, on_menu, icon="play", variant="outline") ``` ```python ui.split_button("Deploy", on_deploy, on_menu, icon="rocket", variant="solid") ``` ##### Size ```python ui.split_button("Build", on_build, on_menu, size="sm") ``` ```python ui.split_button("Build", on_build, on_menu, size="md") ``` ```python ui.split_button("Build", on_build, on_menu, size="lg") ``` ##### Content ```python ui.split_button("Merge", on_merge, on_menu) ``` ```python ui.split_button("Merge", on_merge, on_menu, icon="git-merge") ``` ##### States and events ```python ui.split_button("Deploy", on_press, on_menu, tint="success") ``` ```python ui.split_button("Run", on_press, on_menu, disabled=True) ``` #### Events Split button has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `()` | Message or callable sent on press. `None` disables the control. | | `on_menu` | `()` | Message or callable for the menu button. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Runner(pz.App): def __init__(self): self.menu_open = False self.last = "nothing yet" def run(self, how="run"): self.last, self.menu_open = how, False def view(self): button = ui.split_button("Run", self.run, # on_press: the main action lambda: setattr(self, "menu_open", True), # on_menu: the arrow icon="play") menu = ui.menu([ui.MenuItem("Debug", lambda: self.run("debug"), icon="bug")]) return pz.column([ ui.popover(button, menu if self.menu_open else None, y=32, on_dismiss=lambda: setattr(self, "menu_open", False)), ui.label(f"Last: {self.last}"), ], spacing=8) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Run: how: str = "run" class Runner(pz.App): menu_open = False last = "nothing yet" def update(self, message): match message: case Run(how): self.last, self.menu_open = how, False case "menu": self.menu_open = True case "dismiss": self.menu_open = False def view(self): menu = ui.menu([ui.MenuItem("Debug", Run("debug"), icon="bug")]) return ui.popover(ui.split_button("Run", Run(), "menu", icon="play"), menu if self.menu_open else None, y=32, on_dismiss="dismiss") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: menu_open: bool = False last: str = "nothing yet" def view(state, set_state): run = lambda how: set_state(last=how, menu_open=False) menu = ui.menu([ui.MenuItem("Debug", lambda: run("debug"), icon="bug")]) return ui.popover( ui.split_button("Run", lambda: run("run"), lambda: set_state(menu_open=True), icon="play"), menu if state.menu_open else None, y=32, on_dismiss=lambda: set_state(menu_open=False)) ``` #### Properties and API ##### `ui.split_button` ```python split_button( content, on_press=None, on_menu=None, *, icon=None, variant='filled', tint=None, size='md', disabled=False, tooltip=None, theme=None, ) ``` A button with a separate arrow for more options. `on_press` runs the main action and `on_menu` usually opens a `ui.menu` in a `ui.popover`. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Button text. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `variant` | `"filled"` | As in `ui.button`. | | `tint` | `None` | As in `ui.button`. | | `size` | `"md"` | `"xs"`, `"sm"`, `"md"` or `"lg"`. | | `disabled` | `False` | Disables both halves. | | `tooltip` | `None` | Tooltip of the main half. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_press`, `on_menu` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#split_button) #### Related - [Button](https://albakore.github.io/pyzed/library/button/): The themed button: variants, sizes, icons and shortcuts. - [Menu](https://albakore.github.io/pyzed/library/menu/): A context menu with icons, shortcuts and checks. - [Popover](https://albakore.github.io/pyzed/library/popover/): Floating content at a point: context menus, color pickers. ### Stack > Layers children on top of each other; `pin` places one at x, y. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/stack/ :::tip[In plain words] Puts things on top of each other, like sheets of paper. ::: Layers its children on top of each other, the last one on top: the basis of layers, modals and notifications. `pz.pin(child, x=, y=)` places a child at a position inside the stack. `pz.stack` · Category: [Layout](https://albakore.github.io/pyzed/library/#layout) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#stack) **Code:** ```python t = pz.theme.current() pz.stack([ pz.container(width=320, height=180, bg=t.element, radius=10), pz.pin(pz.container(ui.label("pinned at 24, 24"), padding=10, bg=t.panel, radius=6, border_color=t.border, border_width=1), x=24, y=24), pz.pin(ui.count_badge(3), x=290, y=8), pz.pin(pz.container(ui.label("on top", color="#ffffff"), padding=10, bg=t.accent, radius=6), x=150, y=110), ], width=320, height=180) ``` #### When to use - For badges over icons, overlays, and positioning things freely. #### Usage ```python import pyzed as pz from pyzed import ui t = pz.theme.current() pz.stack([ pz.container(width=320, height=180, bg=t.element, radius=10), pz.pin(pz.container(ui.label("pinned at 24, 24"), padding=10, bg=t.panel, radius=6, border_color=t.border, border_width=1), x=24, y=24), pz.pin(ui.count_badge(3), x=290, y=8), pz.pin(pz.container(ui.label("on top", color="#ffffff"), padding=10, bg=t.accent, radius=6), x=150, y=110), ], width=320, height=180) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python t = pz.theme.current() pz.stack([pz.container(width=180, height=100, bg=t.element, radius=10), pz.container(ui.label("on top"), center=True, width=180, height=100)]) ``` ```python t = pz.theme.current() pz.stack([pz.container(width=180, height=100, bg=t.element, radius=10), pz.pin(ui.count_badge(3), x=150, y=8)], width=180, height=100) ``` ```python pz.stack([pz.container(ui.icon_button("bell", on_press, size="lg"), padding=6), pz.pin(ui.indicator("error", size=8), x=24, y=6)], width=40, height=40) ``` #### Events Stack has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.stack` ```python stack(children=None, *, width=None, height=None) ``` Layers its children on top of each other, the last one on top. The basis for layers, modals and notifications. | Property | Default | Description | | --- | --- | --- | | `children` | `None` | List of children. Nested lists are flattened and `None` and `False` are ignored, so you can write `cond and widget`. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#stack) ##### `pz.pin` ```python pin(content, *, x=0.0, y=0.0, width=None, height=None) ``` Places `content` at `(x, y)` inside a box. Use it in a `stack` to position popovers and context menus. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `x` | `0.0` | Horizontal position. | | `y` | `0.0` | Vertical position. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#pin) #### Related - [Layer](https://albakore.github.io/pyzed/library/layer/): Draws an overlay over your view; clicking outside dismisses it. - [Popover](https://albakore.github.io/pyzed/library/popover/): Floating content at a point: context menus, color pickers. - [Container](https://albakore.github.io/pyzed/library/container/): Size, padding, alignment, background, border and shadow for one child. ### Stat > A dashboard number with change and sparkline. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/stat/ :::tip[In plain words] A big number with its name and whether it went up or down, like on a dashboard. ::: A dashboard tile: a title, a large value, an optional change (`delta`, shown as `+4.2%` in green or red) and an optional `trend` drawn as a sparkline. `ui.stat` · Category: [Data](https://albakore.github.io/pyzed/library/#data) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#stat) **Code:** ```python pz.row([ ui.stat("Users", "1,284", delta=12.5, trend=[3, 5, 4, 6, 8, 7, 9], width=200), ui.stat("Errors", "37", delta=-8.0, width=200), ui.stat("Build time", "1m 12s", width=200), ], spacing=12) ``` #### When to use - For key numbers at the top of a dashboard or report. #### Usage ```python import pyzed as pz from pyzed import ui pz.row([ ui.stat("Users", "1,284", delta=12.5, trend=[3, 5, 4, 6, 8, 7, 9], width=200), ui.stat("Errors", "37", delta=-8.0, width=200), ui.stat("Build time", "1m 12s", width=200), ], spacing=12) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python ui.stat("Build time", "1m 12s", width=190) ``` ```python ui.stat("Users", "1,284", delta=12.5, width=190) ``` ```python ui.stat("Errors", "37", delta=-8.0, width=190) ``` ```python ui.stat("Revenue", "$9.4k", delta=4.2, trend=[3, 5, 4, 6, 8, 7, 9], width=190) ``` ##### States and events With `inverse=True` a drop is good news (green), for errors or latency. ```python ui.stat("Errors", "12", delta=-8.0, inverse=True, icon="bug", width=180) ``` ```python ui.stat("Users", "1,204", delta=4.2, icon="users", on_press=on_press, width=180) ``` #### Events Stat has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `()` | Makes the card clickable. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Dashboard(pz.App): def __init__(self): self.detail = None def view(self): return pz.column([ pz.row([ui.stat("Users", "1,284", delta=12.5, width=200, on_press=lambda: setattr(self, "detail", "Users")), # the whole card ui.stat("Errors", "37", delta=-8.0, width=200, on_press=lambda: setattr(self, "detail", "Errors"))], spacing=12), ui.muted(f"Details of {self.detail}" if self.detail else "Click a number"), ], spacing=8) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Open: metric: str class Dashboard(pz.App): detail = None def update(self, message): match message: case Open(metric): self.detail = metric def view(self): return pz.row([ui.stat(m, v, width=200, on_press=Open(m)) for m, v in (("Users", "1,284"), ("Errors", "37"))], spacing=12) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: detail: str = "" def view(state, set_state): return pz.row([ui.stat(m, v, width=200, on_press=lambda m=m: set_state(detail=m)) for m, v in (("Users", "1,284"), ("Errors", "37"))], spacing=12) ``` #### Properties and API ##### `ui.stat` ```python stat( title, value, *, delta=None, trend=None, width=None, icon=None, inverse=False, on_press=None, theme=None, ) ``` A dashboard number: title, large value, optional change (`+4.2%`) and sparkline. | Property | Default | Description | | --- | --- | --- | | `title` | *required* | Title. | | `value` | *required* | Current value. | | `delta` | `None` | Change in %; green if positive, red otherwise. | | `trend` | `None` | Values for the sparkline. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `icon` | `None` | Icon before the title. | | `inverse` | `False` | Colors a drop green and a rise red (errors, latency…). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#stat) #### Related - [Sparkline](https://albakore.github.io/pyzed/library/sparkline/): A tiny line chart for trends. - [Bar chart](https://albakore.github.io/pyzed/library/bar-chart/): A vertical bar chart with labels. - [Donut](https://albakore.github.io/pyzed/library/donut/): A donut chart with a label in the middle. ### Status bar > The bottom bar: diagnostics, cursor position, language. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/status-bar/ :::tip[In plain words] The thin bar at the bottom of the window with small facts: errors, line number, language. ::: The bottom bar with items at the `start` and `end`. `ui.status_item` shows an icon and/or text, can be pressed, `selected` (a dock that is open) and carry a `tooltip` with `keys`. `ui.status_bar` · Category: [Workspace](https://albakore.github.io/pyzed/library/#workspace) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#status_bar) **Code:** ```python ui.status_bar( [ui.status_item(icon="panel-left", on_press=on_toggle, selected=True, tooltip="Project panel", keys="ctrl-b"), ui.status_item("0", icon="circle-x"), ui.status_item("2", icon="triangle-alert", icon_color="warning")], [ui.status_item("Ln 12, Col 8"), ui.status_item("UTF-8"), ui.status_item("Python", icon="file-code")], ) ``` #### When to use - For always-visible state: errors and warnings, cursor position, language, git branch. #### Usage ```python from pyzed import ui ui.status_bar( [ui.status_item(icon="panel-left", on_press=on_toggle, selected=True, tooltip="Project panel", keys="ctrl-b"), ui.status_item("0", icon="circle-x"), ui.status_item("2", icon="triangle-alert", icon_color="warning")], [ui.status_item("Ln 12, Col 8"), ui.status_item("UTF-8"), ui.status_item("Python", icon="file-code")], ) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Items ```python ui.status_item("Ln 12, Col 8") ``` ```python ui.status_item("Python", icon="file-code") ``` ```python ui.status_item("2", icon="triangle-alert", icon_color="warning") ``` ```python ui.status_item(icon="panel-left", on_press=on_toggle, selected=True) ``` ```python ui.status_item("main", icon="git-branch", color="accent") ``` ##### Bar ```python pz.container(ui.status_bar([ui.status_item("0", icon="circle-x")], [ui.status_item("UTF-8"), ui.status_item("Python")]), width=420) ``` #### Events Status bar has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `()` | Message or callable sent on press. `None` disables the control. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Ide(pz.App): def __init__(self): self.show_left = True def view(self): return ui.status_bar( [ui.status_item(icon="panel-left", selected=self.show_left, tooltip="Project panel", on_press=lambda: setattr(self, "show_left", not self.show_left))], [ui.status_item("Python", icon="file-code")], ) ``` **Declarative:** ```python class Ide(pz.App): show_left = True def update(self, message): if message == "toggle left": self.show_left = not self.show_left def view(self): return ui.status_bar([ui.status_item(icon="panel-left", on_press="toggle left", selected=self.show_left)]) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: show_left: bool = True def view(state, set_state): return ui.status_bar([ui.status_item(icon="panel-left", selected=state.show_left, on_press=lambda: set_state(show_left=not state.show_left))]) ``` #### Properties and API ##### `ui.status_bar` ```python status_bar(start=(), end=(), *, height=28, theme=None) ``` The bottom status bar. | Property | Default | Description | | --- | --- | --- | | `start` | `()` | Widgets at the start (left). | | `end` | `()` | Widgets at the end (right). | | `height` | `28` | Height. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#status_bar) ##### `ui.status_item` ```python status_item( content=None, on_press=None, *, icon=None, color=None, icon_color=None, selected=False, tooltip=None, keys=None, theme=None, ) ``` An icon and/or text in the status bar (diagnostics, cursor position, language…). | Property | Default | Description | | --- | --- | --- | | `content` | `None` | Text. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `color` | `None` | Text or icon color. | | `icon_color` | `None` | Icon color: a theme token or a hex color. | | `selected` | `False` | Marks it as selected. | | `tooltip` | `None` | Tooltip text. | | `keys` | `None` | Shortcut shown at the end, written as a string: `"ctrl-s"`, `"cmd-k cmd-s"`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#status_item) #### Related - [Workspace](https://albakore.github.io/pyzed/library/workspace/): The layout of an editor-style window: title bar, docks, center, status bar. - [Title bar](https://albakore.github.io/pyzed/library/title-bar/): The top bar with project and branch pickers. - [Count badge](https://albakore.github.io/pyzed/library/count-badge/): A round counter that shows 99+ above its max. ### Switch > An on/off switch for settings that apply at once. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/switch/ :::tip[In plain words] An on/off switch, like a light switch, for settings that change right away. ::: An on/off toggle in the theme's accent color. `on_toggle` receives the new `bool`. `ui.switch` · Category: [Forms](https://albakore.github.io/pyzed/library/#forms) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#switch) **Code:** ```python pz.column([ ui.switch(True, on_toggle, label="Autosave"), ui.switch(False, on_toggle, label="Vim mode"), ], spacing=12) ``` #### When to use - For settings that take effect immediately (Wi-Fi, autosave, dark mode). - Put it on the right of a [Field](https://albakore.github.io/pyzed/library/field/) to build settings screens. #### Usage ```python import pyzed as pz from pyzed import ui class Settings(pz.App): def __init__(self): self.autosave = True def view(self): return ui.switch(self.autosave, lambda on: setattr(self, "autosave", on), label="Autosave") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### State ```python ui.switch(True, on_toggle, label="Autosave") ``` ```python ui.switch(False, on_toggle, label="Autosave") ``` ```python ui.switch(True, label="Sync (managed)") ``` ```python ui.switch(True, on_toggle) ``` ##### States and events ```python ui.switch(True, on_toggle, label="Locked", disabled=True) ``` ```python ui.switch(True, on_toggle, label="Small", size="sm") ``` ```python ui.switch(True, on_toggle, label="Large", size="lg") ``` ##### Base widget The `pz.*` widget underneath: no theme, every color and size is yours. ```python pz.toggler(True, "pz.toggler", on_toggle=on_toggle, accent="#a1c181", size=22) ``` #### Events Switch has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_toggle` | `ui.switch`, `pz.toggler` | `(checked)` | Callable that receives the new `bool` (or a message to send). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Settings(pz.App): def __init__(self): self.autosave = True def set_autosave(self, on): # on_toggle: the new state self.autosave = on def view(self): return pz.column([ ui.switch(self.autosave, self.set_autosave, label="Autosave"), ui.label("Saving as you type" if self.autosave else "Save with Ctrl+S"), ], spacing=8) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class SetAutosave: on: bool class Settings(pz.App): autosave = True def update(self, message): match message: case SetAutosave(on): self.autosave = on def view(self): return ui.switch(self.autosave, SetAutosave, label="Autosave") ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: autosave: bool = True def view(state, set_state): return ui.switch(state.autosave, lambda on: set_state(autosave=on), label="Autosave") ``` #### Tips :::tip Once clicked or reached with Tab it has the keyboard focus (a ring shows when you use the keys): Space or Enter flips it. ::: #### Properties and API ##### `ui.switch` ```python switch( checked, on_toggle=None, *, label=None, size='md', disabled=False, id=None, theme=None, ) ``` An on/off switch. | Property | Default | Description | | --- | --- | --- | | `checked` | *required* | Current state. | | `label` | `None` | Label text. | | `size` | `"md"` | `"sm"`, `"md"` or `"lg"`. | | `disabled` | `False` | Greys it out and ignores clicks. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_toggle` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#switch) ##### `pz.toggler` ```python toggler( checked, label=None, *, on_toggle=None, size=None, text_size=None, accent=None, bg=None, border_color=None, knob_color=None, color=None, ) ``` An on/off switch. | Property | Default | Description | | --- | --- | --- | | `checked` | *required* | Current state. | | `label` | `None` | Label text. | | `size` | `None` | Switch height. | | `text_size` | `None` | Text size. | | `accent` | `None` | Accent color (active part). | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `border_color` | `None` | Border color. | | `knob_color` | `None` | Knob color. | | `color` | `None` | Text or icon color. | Events: `on_toggle` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#toggler) #### Related - [Checkbox](https://albakore.github.io/pyzed/library/checkbox/): A checkbox with an optional label. - [Field](https://albakore.github.io/pyzed/library/field/): A settings row: title and description left, control right. - [Settings group](https://albakore.github.io/pyzed/library/settings-group/): A titled block of field rows, for settings screens. ### Tab bar > Editor tabs with icons, dirty dots and close buttons. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/tab-bar/ :::tip[In plain words] The tabs at the top of an editor, one per open document. ::: A row of editor tabs with optional controls at the start and end. `ui.Tab.for_file(path)` creates a tab with the file's name, icon and path as id. `dirty=True` shows a dot that turns into the close button on hover, `preview=True` draws the name in italics, and `status` tints it with a git color. `on_select(id)` and `on_close(id)` receive the tab id. `ui.tab_bar` · Category: [Navigation](https://albakore.github.io/pyzed/library/#navigation) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#tab_bar) **Code:** ```python ui.tab_bar( [ui.Tab.for_file("src/main.rs"), ui.Tab.for_file("src/app.rs", dirty=True, status="modified"), ui.Tab.for_file("README.md", preview=True)], "src/main.rs", on_select=on_select, on_close=on_close, start=[ui.icon_button("arrow-left", on_back, size="sm"), ui.icon_button("arrow-right", on_forward, size="sm")], end=[ui.icon_button("plus", on_new, size="sm"), ui.icon_button("columns-2", on_split, size="sm")], ) ``` #### When to use - For open documents in an editor, or any set of views the user opens and closes. #### Usage ```python import pyzed as pz from pyzed import ui class Editor(pz.App): def __init__(self): self.open, self.active = ["main.py", "app.py"], "main.py" def close(self, path): i = self.open.index(path) self.open.remove(path) if self.active == path: self.active = self.open[min(i, len(self.open) - 1)] if self.open else None def view(self): return ui.tab_bar([ui.Tab.for_file(p) for p in self.open], self.active, on_select=lambda p: setattr(self, "active", p), on_close=self.close) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Tabs ```python pz.container(ui.tab_bar([ui.Tab.for_file("main.rs"), ui.Tab.for_file("app.rs")], "main.rs", on_close=on_close), width=400) ``` ```python pz.container(ui.tab_bar([ui.Tab.for_file("main.rs"), ui.Tab.for_file("notes.md", dirty=True)], "main.rs", on_close=on_close), width=400) ``` ```python pz.container(ui.tab_bar([ui.Tab.for_file("README.md", preview=True)], "README.md", on_close=on_close), width=400) ``` ```python pz.container(ui.tab_bar([ui.Tab.for_file("app.py", status="modified"), ui.Tab.for_file("new.py", status="created")], "app.py", on_close=on_close), width=400) ``` ```python pz.container(ui.tab_bar([ui.Tab("home", "Home", icon="house"), ui.Tab("logs", "Logs", icon="scroll-text")], "home", on_select=on_select), width=400) ``` ##### Controls ```python pz.container(ui.tab_bar([ui.Tab.for_file("main.rs")], "main.rs", on_close=on_close, start=[ui.icon_button("arrow-left", on_back, size="sm")], end=[ui.icon_button("plus", on_new, size="sm")]), width=400) ``` ```python pz.row([ui.tab(ui.Tab.for_file("main.rs"), active=True), ui.tab(ui.Tab.for_file("app.rs"), active=False, dimmed=True)]) ``` ##### States and events A middle click closes a tab, `on_context(id)` runs on a right click and `on_new` on a double click of the empty space. ```python ui.tab_bar([ui.Tab("app", "app.py", icon="file", pinned=True), ui.Tab("ui", "ui.py", icon="file")], "ui", on_close=on_close, on_context=on_context, on_new=on_new) ``` #### Events Tab bar has **7 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_select` | `ui.tab_bar`, `ui.tab` | `(tab_id)` | Callable that receives the chosen item. | | `on_close` | `ui.tab_bar`, `ui.tab` | `(tab_id)` | Message or callable sent when the X is pressed. | | `on_drag` | `ui.tab_bar` | `(tab_id)` | Called with the tab id when a tab starts being dragged. | | `on_drop` | `ui.tab_bar` | `(tab_id, event)` | Called with the tab id and the `Event` when the dragged tab is released: `event.window_x`/`window_y` (outside the window if it was dropped outside) and `event.screen`. | | `on_drag_over` | `ui.tab_bar` | `(index)` | While `dragging` is set: called with the insertion index under the pointer, or `None` when it leaves the bar. | | `on_context` | `ui.tab_bar` | `(tab_id)` | Called with the id of a tab that is right-clicked. | | `on_new` | `ui.tab_bar` | `()` | Sent on a double click of the empty space after the tabs. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Editor(pz.App): def __init__(self): self.open, self.active = ["main.py", "app.py"], "main.py" self.untitled = 0 def close(self, path): # on_close: the id of the tab i = self.open.index(path) self.open.remove(path) if self.active == path: self.active = self.open[min(i, len(self.open) - 1)] if self.open else None def new(self): # on_new: double click after the tabs self.untitled += 1 self.open.append(f"untitled-{self.untitled}") self.active = self.open[-1] def view(self): return ui.tab_bar([ui.Tab.for_file(p) for p in self.open], self.active, on_select=lambda p: setattr(self, "active", p), on_close=self.close, on_new=self.new, on_context=lambda p: print("menu for", p)) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Activate: path: str @dataclass class Close: path: str class Editor(pz.App): open, active = ["main.py", "app.py"], "main.py" def update(self, message): match message: case Activate(path): self.active = path case Close(path): self.open = [p for p in self.open if p != path] self.active = self.open[0] if self.open else None def view(self): return ui.tab_bar([ui.Tab.for_file(p) for p in self.open], self.active, on_select=Activate, on_close=Close) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: open: tuple = ("main.py", "app.py") active: str = "main.py" def view(state, set_state): def close(path): rest = tuple(p for p in state.open if p != path) set_state(open=rest, active=state.active if state.active != path else (rest[0] if rest else "")) return ui.tab_bar([ui.Tab.for_file(p) for p in state.open], state.active, on_select=lambda p: set_state(active=p), on_close=close) ``` #### Properties and API ##### `ui.tab_bar` ```python tab_bar( tabs, active, *, on_select=None, on_close=None, start=(), end=(), height=32, on_drag=None, on_drop=None, on_drag_over=None, dragging=None, drop_index=None, on_context=None, on_new=None, theme=None, ) ``` A row of tabs with optional controls at the start and end (navigation, split, +). The close button appears on the active tab and on hover. Tabs can be dragged to reorder them or out of the window: see [Draggable tabs](https://albakore.github.io/pyzed/guides/windows/#draggable-tabs-and-detachable-windows). | Property | Default | Description | | --- | --- | --- | | `tabs` | *required* | List of `Tab`. | | `active` | *required* | Id of the active tab. | | `start` | `()` | Widgets at the start (left). | | `end` | `()` | Widgets at the end (right). | | `height` | `32` | Height. | | `dragging` | `None` | Id of the tab being dragged (dims it and turns on `on_drag_over`). | | `drop_index` | `None` | Draws the insertion mark before the tab at this index (`len(tabs)`: after the last one). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_select`, `on_close`, `on_drag`, `on_drop`, `on_drag_over`, `on_context`, `on_new` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#tab_bar) ##### `ui.Tab` ```python @dataclass class Tab(id, label, icon=None, icon_color=None, dirty=False, preview=False, status=None, pinned=False, tooltip=None) ``` A tab. `Tab.for_file(path, **kwargs)` creates it with the file's name and icon. | Property | Default | Description | | --- | --- | --- | | `id` | *required* | Stable identifier used to focus or scroll it with a `Command`. | | `label` | *required* | Label text. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `icon_color` | `None` | Icon color: a theme token or a hex color. | | `dirty` | `False` | Unsaved changes (shows a dot). | | `preview` | `False` | Preview tab (in italics). | | `status` | `None` | Git status (tints the name). | | `pinned` | `False` | Shows only the icon, has no close button and goes first in `tab_bar`. | | `tooltip` | `None` | Text shown on hover (the full path…). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#tab) ##### `ui.tab` ```python tab(item, *, active, on_select=None, on_close=None, height=32, dimmed=False, theme=None) ``` A single tab. You normally use `tab_bar`. | Property | Default | Description | | --- | --- | --- | | `item` | *required* | The `Tab`. | | `active` | *required* | Whether it is the active one. | | `height` | `32` | Height. | | `dimmed` | `False` | Mutes the label (the tab being dragged). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_select`, `on_close` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#tab-1) #### Related - [Toolbar](https://albakore.github.io/pyzed/library/toolbar/): The bar under the tabs: breadcrumbs and buffer actions. - [Breadcrumbs](https://albakore.github.io/pyzed/library/breadcrumbs/): `src › main.rs › fn main`, optionally clickable. - [Segmented](https://albakore.github.io/pyzed/library/segmented/): A group of mutually exclusive text buttons. ### Table > A data table with a fixed header, sorting and selection. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/table/ :::tip[In plain words] Rows and columns of data, like a spreadsheet you can sort by clicking a column. ::: A data table with a fixed header, optional sorting and row selection. Columns are `ui.Column` objects whose `key` is a dict key, an attribute name or a function of the row; `render` turns a value into any widget. The table sorts the rows itself by the column whose **title** is `sort_by`: you only store that title and the direction. `ui.table` · Category: [Data](https://albakore.github.io/pyzed/library/#data) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#table) **Code:** ```python rows = [ {"name": "render.rs", "lang": "Rust", "lines": 1840}, {"name": "app.py", "lang": "Python", "lines": 512}, {"name": "theme.py", "lang": "Python", "lines": 730}, {"name": "docs.yml", "lang": "YAML", "lines": 64}, ] pz.container(ui.table( [ui.Column("File", "name"), ui.Column("Language", "lang", width=120), ui.Column("Lines", "lines", width=80, align="end")], rows, sort_by="Lines", descending=True, on_sort=on_sort, selected=rows[1], striped=True, ), width=520) ``` #### When to use - For records with several comparable fields: files, users, processes, results. - For a single column of items, a list of [List items](https://albakore.github.io/pyzed/library/list-item/) is lighter. #### Usage ```python import pyzed as pz from pyzed import ui class Files(pz.App): def __init__(self): self.rows = [{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}] self.sort_by, self.descending, self.selected = "Lines", True, None def sort(self, title): self.descending = not self.descending if self.sort_by == title else False self.sort_by = title def view(self): return ui.table( [ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")], self.rows, sort_by=self.sort_by, descending=self.descending, on_sort=self.sort, on_row_press=lambda row: setattr(self, "selected", row), selected=self.selected, ) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python pz.container(ui.table([ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")], [{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}, {"name": "ui.py", "lines": 1290}]), width=320) ``` ```python pz.container(ui.table([ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")], [{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}, {"name": "ui.py", "lines": 1290}], striped=True), width=320) ``` ```python rows = [{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}, {"name": "ui.py", "lines": 1290}] pz.container(ui.table([ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")], rows, selected=rows[1]), width=320) ``` ```python pz.container(ui.table([ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")], [{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}, {"name": "ui.py", "lines": 1290}], sort_by="Lines", descending=True, on_sort=on_sort), width=320) ``` ```python pz.container(ui.table([ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")], [{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}, {"name": "ui.py", "lines": 1290}], row_height=24), width=320) ``` ##### Cells ```python rows = [{"job": "build", "state": "passed"}, {"job": "lint", "state": "failed"}] tint = {"passed": "success", "failed": "error"} pz.container(ui.table([ui.Column("Job", "job"), ui.Column("State", "state", width=110, render=lambda s: ui.badge(s, tint=tint[s]))], rows), width=320) ``` ```python people = [("Ana", 31), ("Luis", 27)] pz.container(ui.table([ui.Column("Name", lambda p: p[0]), ui.Column("Age", lambda p: p[1], width=70, align="end")], people), width=320) ``` ##### States and events `on_row_double_press(row)` opens a row and `on_row_context(row)` shows a context menu. ```python rows = [{"name": "app.py", "size": 4}, {"name": "ui.py", "size": 12}, {"name": "README.md", "size": 2}] ui.table(["name", "size"], rows, selected=[rows[0], rows[2]], on_row_press=on_press, on_row_double_press=on_open, on_row_context=on_context, height=130) ``` ```python ui.table(["name", "size"], [], empty="No files yet", height=100) ``` #### Examples ##### Custom cells `render` receives the value and returns a widget, here a badge. **Code:** ```python rows = [{"job": "build", "state": "passed"}, {"job": "lint", "state": "failed"}, {"job": "docs", "state": "running"}] tint = {"passed": "success", "failed": "error", "running": "warning"} pz.container(ui.table( [ui.Column("Job", "job"), ui.Column("State", "state", width=120, render=lambda s: ui.badge(s, tint=tint[s]))], rows, ), width=400) ``` #### Events Table has **4 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_sort` | `(title)` | Callable that receives the clicked title. | | `on_row_press` | `(row)` | Callable that receives the clicked row. | | `on_row_double_press` | `(row)` | Called with the row on a double click (open, edit…). | | `on_row_context` | `(row)` | Called with the row on a right click (a context menu). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Files(pz.App): def __init__(self): self.rows = [{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}] self.sort_by, self.descending = "Lines", True self.selected, self.opened = None, None def sort(self, title): # on_sort: the clicked column title self.descending = not self.descending if self.sort_by == title else False self.sort_by = title def view(self): key = "name" if self.sort_by == "File" else "lines" rows = sorted(self.rows, key=lambda r: r[key], reverse=self.descending) return ui.table( [ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")], rows, sort_by=self.sort_by, descending=self.descending, on_sort=self.sort, selected=self.selected, on_row_press=lambda row: setattr(self, "selected", row), # click on_row_double_press=lambda row: setattr(self, "opened", row), # double click on_row_context=lambda row: print("menu for", row["name"]), # right click ) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Sort: title: str @dataclass class Select: row: dict class Files(pz.App): rows = [{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}] sort_by, descending, selected = "Lines", True, None def update(self, message): match message: case Sort(title): self.descending = not self.descending if title == self.sort_by else False self.sort_by = title case Select(row): self.selected = row def view(self): return ui.table([ui.Column("File", "name"), ui.Column("Lines", "lines", width=80)], self.rows, sort_by=self.sort_by, descending=self.descending, selected=self.selected, on_sort=Sort, on_row_press=Select) ``` **Functional:** ```python from dataclasses import dataclass ROWS = ({"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}) @dataclass(frozen=True) class State: sort_by: str = "Lines" descending: bool = True selected: str = "" def view(state, set_state): key = "name" if state.sort_by == "File" else "lines" rows = sorted(ROWS, key=lambda r: r[key], reverse=state.descending) return ui.table( [ui.Column("File", "name"), ui.Column("Lines", "lines", width=80)], rows, sort_by=state.sort_by, descending=state.descending, selected=next((r for r in rows if r["name"] == state.selected), None), on_sort=lambda t: set_state(sort_by=t, descending=not state.descending if t == state.sort_by else False), on_row_press=lambda row: set_state(selected=row["name"])) ``` #### Properties and API ##### `ui.table` ```python table( columns, rows, *, sort_by=None, descending=False, on_sort=None, on_row_press=None, selected=None, striped=False, row_height=30, height=None, on_row_double_press=None, on_row_context=None, empty=None, theme=None, ) ``` A data table with a fixed header, optional sorting and row selection. Sorting happens here when `sort_by` names a column: clicking a header calls `on_sort(title)` and you update `sort_by`/`descending` in your state. Rows are virtualized: only the ones in view are built, so hundreds of thousands of rows scroll smoothly. | Property | Default | Description | | --- | --- | --- | | `columns` | *required* | `ui.Column` or plain keys. | | `rows` | *required* | Dicts or objects. | | `sort_by` | `None` | Title of the column to sort by. | | `descending` | `False` | Descending order. | | `selected` | `None` | The row to highlight, or a list or set of rows (multiple selection). | | `striped` | `False` | Shaded alternating rows. | | `row_height` | `30` | Height of each row. | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `empty` | `None` | Text or widget shown in place of the rows when there are none. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_sort`, `on_row_press`, `on_row_double_press`, `on_row_context` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#table) ##### `ui.Column` ```python @dataclass class Column(title, key, width='fill', align='start', render=None, sortable=True) ``` A column of `ui.table`. `key` is a dict key, an attribute name or a function of the row; `render` (optional) turns the value into a widget. `width` is `"fill"`, a number or a portion such as `"fill:2"`. | Property | Default | Description | | --- | --- | --- | | `title` | *required* | Header (and name used for sorting). | | `key` | *required* | How to get the value from each row. | | `width` | `"fill"` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `align` | `"start"` | `"start"`, `"center"` or `"end"`. | | `render` | `None` | Function value → widget. | | `sortable` | `True` | Whether the header can be clicked to sort. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#column) #### Related - [List item](https://albakore.github.io/pyzed/library/list-item/): A list row with icon, text and an end slot. - [Virtual list](https://albakore.github.io/pyzed/library/virtual-list/): A list that only builds the rows in view, for millions of items. - [Stat](https://albakore.github.io/pyzed/library/stat/): A dashboard number with change and sparkline. - [Settings group](https://albakore.github.io/pyzed/library/settings-group/): A titled block of field rows, for settings screens. ### Terminal > A read-only terminal view with ANSI colors. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/terminal/ :::tip[In plain words] Shows the text a program prints, with its colors, like a terminal window. ::: A read-only view that understands ANSI colors and stays scrolled to the end. Feed it the output of a process you run (for example with `subprocess` in a thread and `pz.post`). It also accepts lines of `(text, color)` segments; `ui.ansi(text)` converts ANSI text into those segments. `ui.terminal` · Category: [Code and tools](https://albakore.github.io/pyzed/library/#code-and-tools) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#terminal) **Code:** ```python out = ("$ pytest -q\n\x1b[32m........................\x1b[0m\n\x1b[32m24 passed\x1b[0m in 1.21s\n" "$ maturin develop --release\n\x1b[2m Compiling pyzed v0.4.0\x1b[0m\n" "\x1b[32m✓\x1b[0m Installed pyzed-0.4.0\n$ ") pz.container(ui.terminal(out), width=560, height=190) ``` #### When to use - To show build output, test runs, server logs or any command's output. #### Usage ```python import pyzed as pz from pyzed import ui out = ("$ pytest -q\n\x1b[32m........................\x1b[0m\n\x1b[32m24 passed\x1b[0m in 1.21s\n" "$ maturin develop --release\n\x1b[2m Compiling pyzed v0.4.0\x1b[0m\n" "\x1b[32m✓\x1b[0m Installed pyzed-0.4.0\n$ ") pz.container(ui.terminal(out), width=560, height=190) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python pz.container(ui.terminal("$ ls\nmain.py notes.md pyproject.toml\n$ "), width=380, height=80) ``` ```python pz.container(ui.terminal("\x1b[32m✓\x1b[0m 24 passed \x1b[33m!\x1b[0m 1 warning \x1b[31m✗\x1b[0m 0 failed"), width=380, height=50) ``` ```python pz.container(ui.terminal("$ python main.py\nHello", font_size=16), width=380, height=70) ``` ```python pz.container(ui.terminal([[("ok ", "#a1c181"), ("build", None)], [("err ", "#d07277"), ("lint", None)]]), width=380, height=60) ``` #### Events Terminal has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.terminal` ```python terminal(lines, *, font_size=13, id=None, theme=None) ``` A read-only terminal view with ANSI colors. It stays scrolled to the end. | Property | Default | Description | | --- | --- | --- | | `lines` | *required* | Text with ANSI escapes, or a list of lines of `(text, color)` segments. | | `font_size` | `13` | Font size. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#terminal) ##### `ui.ansi` ```python ansi(text) ``` Converts text with ANSI colors into lines of `(text, color_name)` segments. | Property | Default | Description | | --- | --- | --- | | `text` | *required* | Text with ANSI escapes. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#ansi) #### Related - [Console](https://albakore.github.io/pyzed/library/console/): A dev-tools style log with levels, filter, copy and clear. - [Editor](https://albakore.github.io/pyzed/library/editor/): A full code editor: highlighting, folding, minimap, git markers. ### Text > A piece of text with size, color, font and weight. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/text/ :::tip[In plain words] Text with any size, color and font you choose. ::: The base text widget: `size`, `color`, `font`, `weight`, `italic`, `line_height`, alignment and wrapping. In a themed UI prefer [Label](https://albakore.github.io/pyzed/library/label/), which takes its color from the theme. `pz.text` · Category: [Content](https://albakore.github.io/pyzed/library/#content) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#text) **Code:** ```python pz.column([ pz.text("Pyzed", size=36, weight="bold", color="#74ade8"), pz.text("Fast, modern desktop UIs in Python.", size=16, color="#a9afbc"), pz.text("IBM Plex Mono, italic", font="IBM Plex Mono", italic=True, color="#e5c07b"), ], spacing=6, align="center") ``` #### When to use - For text with explicit styles, or custom fonts loaded with `pz.load_font`. #### Usage ```python import pyzed as pz pz.column([ pz.text("Pyzed", size=36, weight="bold", color="#74ade8"), pz.text("Fast, modern desktop UIs in Python.", size=16, color="#a9afbc"), pz.text("IBM Plex Mono, italic", font="IBM Plex Mono", italic=True, color="#e5c07b"), ], spacing=6, align="center") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Size ```python pz.text("Size 12", size=12) ``` ```python pz.text("Size 18", size=18) ``` ```python pz.text("Size 32", size=32) ``` ##### Font and weight ```python pz.text("Bold", size=18, weight="bold") ``` ```python pz.text("Light", size=18, weight="light") ``` ```python pz.text("Italic", size=18, italic=True) ``` ```python pz.text("Monospace 0123", size=16, font="mono") ``` ##### Color and wrapping ```python pz.text("Golden text", size=18, color="#e5c07b") ``` ```python pz.container(pz.text("A long sentence that wraps over several lines, centered.", align_x="center"), width=220) ``` ```python pz.container(pz.text("Taller lines are easier to read in long paragraphs.", line_height=1.8), width=220) ``` #### Events Text has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `pz.text` ```python text( content, *, size=None, color=None, font=None, weight=None, italic=False, line_height=None, align_x=None, align_y=None, width=None, height=None, wrap=True, selectable=None, selection_color=None, ) ``` A piece of text. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `size` | `None` | Font size. | | `color` | `None` | Text or icon color. | | `font` | `None` | `"sans"` (IBM Plex Sans), `"mono"`, `"icons"`, `"serif"` or the name of a family loaded with `load_font`. | | `weight` | `None` | `"thin"`, `"light"`, `"normal"`, `"medium"`, `"semibold"`, `"bold"`, `"black"` or a number (100–900). | | `italic` | `False` | Italic. | | `line_height` | `None` | Line height relative to the size (1.0, 1.5…). | | `align_x` | `None` | Horizontal alignment: `"start"`/`"left"`, `"center"`, `"end"`/`"right"`. | | `align_y` | `None` | Vertical alignment: `"start"`/`"top"`, `"center"`, `"end"`/`"bottom"`. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `wrap` | `True` | Line wrapping. With `False` the text doesn't wrap. | | `selectable` | `None` | `True` lets the mouse select the text (drag, double-click a word, triple-click a block) and Ctrl+C copy it. A string names a selection group: the texts and Markdown of one group form a single selection, in the order they are drawn (the lines of a log, the messages of a chat). | | `selection_color` | `None` | Color behind the selected text. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#text) #### Related - [Label](https://albakore.github.io/pyzed/library/label/): Text with a theme color, size and weight; `muted` for secondary text. - [Rich text](https://albakore.github.io/pyzed/library/rich-text/): One block of text mixing colors, weights and links. - [Icon](https://albakore.github.io/pyzed/library/icon/): Lucide icons by name, and SVG images. ### Thread history > Past conversations, searchable and grouped by day. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/thread-history/ :::tip[In plain words] The list of your earlier chats, sorted by day, with a box to search them. ::: `ui.ThreadHistory` is a component for past conversations: a search box and the threads grouped by when they were last updated (Today, Yesterday, This week, This month, Older). Each row shows the title, an optional `detail` (the model or the agent) and a delete button. `threads` are dicts or objects with `id`, `title`, `updated` (a `time.time()` timestamp) and `detail`; `selected` marks the open one. Picking a thread reports `on_open` and the trash button `on_delete`, both with the thread's id in `event.value`. The component keeps the search text itself. `ui.ThreadHistory` · Category: [AI agents](https://albakore.github.io/pyzed/library/#ai-agents) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#threadhistory) **Code:** ```python import time now = time.time() pz.container(ui.ThreadHistory(threads=[ {"id": "1", "title": "Add a login form", "updated": now - 60, "detail": "Claude"}, {"id": "2", "title": "Fix the failing tests", "updated": now - 900, "detail": "Claude"}, {"id": "3", "title": "Dark theme for the settings", "updated": now - 86400, "detail": "Gemini CLI"}, {"id": "4", "title": "Export the table to CSV", "updated": now - 4 * 86400}, {"id": "5", "title": "First steps", "updated": now - 60 * 86400}, ], selected="1", on_open=on_open, on_delete=on_delete), width=380, height=320) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - In a side panel or a popover of a chat app, to reopen an earlier conversation. #### Usage ```python import pyzed as pz from pyzed import ui class Chats(pz.App): def __init__(self): self.threads = load_threads() # [{"id", "title", "updated", "detail"}, ...] self.open_id = "" def delete(self, ident): self.threads = [t for t in self.threads if t["id"] != ident] def view(self): return ui.ThreadHistory(threads=self.threads, selected=self.open_id, on_open=lambda e: setattr(self, "open_id", e.value), on_delete=lambda e: self.delete(e.value)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### State The search ones are drawn with text typed in the box (the component keeps it). ```python import time now = time.time() threads = [ {"id": "1", "title": "Add a login form", "updated": now - 60, "detail": "Claude"}, {"id": "2", "title": "Fix the failing tests", "updated": now - 86400}, {"id": "3", "title": "Export the table to CSV", "updated": now - 4 * 86400}, ] pz.container(ui.ThreadHistory(threads=threads), width=320, height=260) ``` ```python import time now = time.time() threads = [ {"id": "1", "title": "Add a login form", "updated": now - 60, "detail": "Claude"}, {"id": "2", "title": "Fix the failing tests", "updated": now - 86400}, {"id": "3", "title": "Export the table to CSV", "updated": now - 4 * 86400}, ] pz.container(ui.ThreadHistory(threads=threads, selected="2"), width=320, height=260) ``` ```python pz.container(ui.ThreadHistory(threads=[]), width=320, height=110) ``` ```python import time now = time.time() threads = [ {"id": "1", "title": "Add a login form", "updated": now - 60, "detail": "Claude"}, {"id": "2", "title": "Fix the failing tests", "updated": now - 86400}, {"id": "3", "title": "Export the table to CSV", "updated": now - 4 * 86400}, ] pz.container(ui.ThreadHistory(threads=threads), width=320, height=160) ``` ```python import time now = time.time() threads = [ {"id": "1", "title": "Add a login form", "updated": now - 60, "detail": "Claude"}, {"id": "2", "title": "Fix the failing tests", "updated": now - 86400}, {"id": "3", "title": "Export the table to CSV", "updated": now - 4 * 86400}, ] pz.container(ui.ThreadHistory(threads=threads), width=320, height=110) ``` #### Events Thread history has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Handler gets | When | | --- | --- | --- | | `on_open` | `(event)` | A thread was picked (`event.value` is its id). | | `on_delete` | `(event)` | Delete was pressed on a thread. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python import time class Chats(pz.App): def __init__(self): now = time.time() self.threads = [{"id": "1", "title": "Add a login form", "updated": now - 60}, {"id": "2", "title": "Fix the tests", "updated": now - 900}] self.open_id = "1" def view(self): # event.value is the thread's id return ui.ThreadHistory(threads=self.threads, selected=self.open_id, on_open=lambda e: setattr(self, "open_id", e.value), on_delete=lambda e: self.delete(e.value)) def delete(self, ident): self.threads = [t for t in self.threads if t["id"] != ident] ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class OpenThread: ident: str @dataclass class DeleteThread: ident: str class Chats(pz.App): threads = [{"id": "1", "title": "Add a login form", "updated": 0}] open_id = "" def update(self, message): match message: case OpenThread(ident): self.open_id = ident case DeleteThread(ident): self.threads = [t for t in self.threads if t["id"] != ident] def view(self): return ui.ThreadHistory(threads=self.threads, selected=self.open_id, on_open=lambda e: OpenThread(e.value), on_delete=lambda e: DeleteThread(e.value)) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: threads: tuple = ({"id": "1", "title": "Add a login form", "updated": 0},) open_id: str = "" def view(state, set_state): return ui.ThreadHistory( threads=list(state.threads), selected=state.open_id, on_open=lambda e: set_state(open_id=e.value), on_delete=lambda e: set_state(threads=tuple(t for t in state.threads if t["id"] != e.value))) ``` #### Properties and API ##### `ui.ThreadHistory` ```python class ThreadHistory ``` A component for past conversations: a search box and the threads grouped by day (Today, Yesterday, This week, This month, Older), each with a delete button. | Property | Default | Description | | --- | --- | --- | | `threads` | `None` | Dicts or objects with `id`, `title`, `updated` (a timestamp) and an optional `detail`. | | `selected` | `""` | The id of the open thread. | | `theme` | `None` | Theme. | Events: `on_open`, `on_delete` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#threadhistory) #### Related - [List item](https://albakore.github.io/pyzed/library/list-item/): A list row with icon, text and an end slot. - [Search input](https://albakore.github.io/pyzed/library/search-input/): An input with a magnifying glass, for filtering. - [Virtual list](https://albakore.github.io/pyzed/library/virtual-list/): A list that only builds the rows in view, for millions of items. ### Time picker > A time field with columns of hours and minutes, in 24 or 12 hours. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/time-picker/ :::tip[In plain words] A box for a time of day, with lists of hours and minutes to choose from. ::: `ui.TimePicker` is a field for a time of day. Its popup has a column of hours, one of minutes (every `minute_step` minutes), seconds when the format has `ss` and AM/PM when it has `A` or `h`. ↑ and ↓ move it by one step from the keyboard. `on_change` receives a `datetime.time`. `ui.TimePicker` · Category: [Dates and times](https://albakore.github.io/pyzed/library/#dates-and-times) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#timepicker) **Code:** ```python pz.row([ pz.container(ui.TimePicker(value="14:30", on_change=on_change), width=140, height=290, align_y="start"), pz.container(ui.TimePicker(value="14:30", format="h:mm A", minute_step=15, on_change=on_change), width=140, height=290, align_y="start"), ], spacing=24) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For alarms, opening hours, meetings and reminders. - `format="HH:mm"` is 24 hours; `"h:mm A"` is 12 hours with AM/PM; `"HH:mm:ss"` adds seconds. #### Usage ```python import pyzed as pz from pyzed import ui import datetime class Alarm(pz.App): def __init__(self): self.at = datetime.time(7, 30) def view(self): return ui.field("Wake me at", ui.TimePicker(value=self.at, format="h:mm A", on_change=lambda e: setattr(self, "at", e.value))) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Format ```python ui.TimePicker(value="14:30", on_change=on_change) ``` ```python ui.TimePicker(value="14:30", format="h:mm A", on_change=on_change) ``` ```python ui.TimePicker(value="14:30:15", format="HH:mm:ss", on_change=on_change) ``` ##### Open ```python ui.TimePicker(value="06:15:30", format="HH:mm:ss", on_change=on_change) ``` ```python ui.TimePicker(value="14:30", format="h:mm A", minute_step=15, on_change=on_change) ``` #### Events Time picker has **3 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Handler gets | When | | --- | --- | --- | | `on_change` | `(event)` | Receives `event.value`: a `datetime.time` or `None`. | | `on_open` | `(event)` | The list opened. | | `on_close` | `(event)` | The list closed. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python import datetime class Alarm(pz.App): def __init__(self): self.at = datetime.time(7, 30) def changed(self, event): # on_change: event.value is a datetime.time self.at = event.value def view(self): return pz.column([ ui.TimePicker(value=self.at, format="h:mm A", on_change=self.changed), ui.label(f"Alarm at {ui.format_time(self.at, 'HH:mm')}"), ], spacing=8, width=200) ``` **Declarative:** ```python import datetime from dataclasses import dataclass @dataclass class At: time: datetime.time class Alarm(pz.App): at = datetime.time(7, 30) def update(self, message): match message: case At(time): self.at = time def view(self): return ui.TimePicker(value=self.at, on_change=lambda e: At(e.value)) ``` **Functional:** ```python import datetime from dataclasses import dataclass @dataclass(frozen=True) class State: at: datetime.time = datetime.time(7, 30) def view(state, set_state): return ui.TimePicker(value=state.at, minute_step=15, on_change=lambda e: set_state(at=e.value)) ``` #### Properties and API ##### `ui.TimePicker` ```python class TimePicker ``` A component: a time field with columns of hours and minutes (and seconds, and AM/PM with a 12-hour `format`) in a popup. Once clicked, ↑/↓ change it by `minute_step`. See the [Time picker](https://albakore.github.io/pyzed/library/time-picker/) page. | Property | Default | Description | | --- | --- | --- | | `value` | `None` | The time (`datetime.time`, `"14:30"` or `None`). | | `format` | `"HH:mm"` | `"HH:mm"`, `"HH:mm:ss"`, `"h:mm A"`... | | `placeholder` | `""` | Hint while empty. | | `minute_step` | `5` | Minutes between the ones offered. | | `min` | `None` | The earliest time. | | `max` | `None` | The latest time. | | `clearable` | `True` | Shows an x that empties it. | | `disabled` | `False` | Greys it out. | | `invalid` | `False` | Paints the border in the error color. | Events: `on_change`, `on_open`, `on_close` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#timepicker) ##### `ui.format_time` ```python format_time(value, fmt='HH:mm') ``` Writes a time (or `"14:30"`) with a pattern such as `"h:mm A"`. | Property | Default | Description | | --- | --- | --- | | `value` | *required* | A `datetime.time` or text. | | `fmt` | `"HH:mm"` | The pattern. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#format_time) ##### `ui.parse_time` ```python parse_time(text, fmt='HH:mm') ``` Reads a time: `"14:30"`, `"2:30 PM"`, `"14:30:05"`, with `fmt` first. `None` when it is not one. | Property | Default | Description | | --- | --- | --- | | `text` | *required* | The text. | | `fmt` | `"HH:mm"` | The pattern. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#parse_time) #### Related - [Date picker](https://albakore.github.io/pyzed/library/date-picker/): A date field with a calendar that drops down, in the format you choose. - [Number field](https://albakore.github.io/pyzed/library/number-field/): A number with −/+ buttons, limits, step and suffix. ### Title bar > The top bar with project and branch pickers. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/title-bar/ :::tip[In plain words] The bar at the very top of the window, with the project name and quick buttons. ::: The top bar of the window: widgets at the `start` (project and branch pickers), an optional `center` and widgets at the `end` (account, notifications). `ui.title_button` is the compact button it uses (`pyzed ▾`, `main`), with `chevron` and `muted` styles. `ui.title_bar` · Category: [Workspace](https://albakore.github.io/pyzed/library/#workspace) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#title_bar) **Code:** ```python ui.title_bar( [ui.title_button("pyzed", on_projects, chevron=True), ui.title_button("main", on_branches, icon="git-branch", muted=True)], [ui.facepile(["Ana", "Luis"]), ui.icon_button("bell", on_bell, size="sm"), ui.avatar("KV")], center=ui.muted("notes.py"), ) ``` #### When to use - At the top of a `ui.workspace`, or of any window with `decorations=False`. #### Usage ```python from pyzed import ui ui.title_bar( [ui.title_button("pyzed", on_projects, chevron=True), ui.title_button("main", on_branches, icon="git-branch", muted=True)], [ui.facepile(["Ana", "Luis"]), ui.icon_button("bell", on_bell, size="sm"), ui.avatar("KV")], center=ui.muted("notes.py"), ) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Title buttons ```python ui.title_button("pyzed", on_projects) ``` ```python ui.title_button("pyzed", on_projects, chevron=True) ``` ```python ui.title_button("main", on_branches, icon="git-branch", muted=True) ``` ##### Bar ```python pz.container(ui.title_bar([ui.title_button("pyzed", chevron=True)]), width=420) ``` ```python pz.container(ui.title_bar([], [], center=ui.muted("notes.py — Notes")), width=420) ``` ```python pz.container(ui.title_bar([], [ui.icon_button("bell", on_bell, size="sm"), ui.avatar("KV")]), width=420) ``` #### Events Title bar has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_press` | `()` | Message or callable sent on press. `None` disables the control. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Ide(pz.App): def __init__(self): self.picking = None def view(self): return ui.title_bar([ ui.title_button("pyzed", lambda: setattr(self, "picking", "project"), chevron=True), ui.title_button("main", lambda: setattr(self, "picking", "branch"), icon="git-branch", muted=True), ], center=ui.muted(f"Pick a {self.picking}" if self.picking else "notes.py")) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Pick: what: str class Ide(pz.App): picking = None def update(self, message): match message: case Pick(what): self.picking = what def view(self): return ui.title_bar([ui.title_button("pyzed", Pick("project"), chevron=True), ui.title_button("main", Pick("branch"), icon="git-branch", muted=True)]) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: project: str = "pyzed" projects: tuple = ("pyzed", "notes") def view(state, set_state): nxt = state.projects[(state.projects.index(state.project) + 1) % len(state.projects)] return ui.title_bar([ui.title_button(state.project, lambda: set_state(project=nxt), chevron=True)]) ``` #### Properties and API ##### `ui.title_bar` ```python title_bar(start=(), end=(), *, center=None, height=34, theme=None) ``` The top bar: project and branch pickers on the left, account and actions on the right. | Property | Default | Description | | --- | --- | --- | | `start` | `()` | Widgets at the start (left). | | `end` | `()` | Widgets at the end (right). | | `center` | `None` | Centered widget. | | `height` | `34` | Height. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#title_bar) ##### `ui.title_button` ```python title_button( content, on_press=None, *, icon=None, muted=False, chevron=False, theme=None, ) ``` A compact button for the title bar (`pyzed ▾`, `main`…). | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Text. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `muted` | `False` | Muted text. | | `chevron` | `False` | Adds a ▾. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#title_button) #### Related - [Workspace](https://albakore.github.io/pyzed/library/workspace/): The layout of an editor-style window: title bar, docks, center, status bar. - [Status bar](https://albakore.github.io/pyzed/library/status-bar/): The bottom bar: diagnostics, cursor position, language. - [Facepile](https://albakore.github.io/pyzed/library/facepile/): Overlapping collaborator avatars with +N. - [Window frame](https://albakore.github.io/pyzed/library/window-frame/): Your own title bar, window buttons and menus. ### Toast > Notifications stacked in the bottom-right corner. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/toast/ :::tip[In plain words] A small notification that pops up in a corner and goes away by itself. ::: `ui.toast` draws a notification with a title, a message, actions and a close button; `kind` is `"info"`, `"success"`, `"warning"` or `"error"`. `ui.toasts(base, items)` stacks them in the bottom-right corner over your view. `ui.toast` · Category: [Overlays](https://albakore.github.io/pyzed/library/#overlays) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#toast) **Code:** ```python pz.column([ ui.toast("Saved", "main.py was saved.", kind="success", on_dismiss=on_dismiss), ui.toast("Update available", "Pyzed 0.4 is on PyPI.", kind="info", actions=[ui.button("What's new", on_open, size="sm")], on_dismiss=on_dismiss), ui.toast("Could not connect", kind="error", on_dismiss=on_dismiss), ], spacing=8) ``` #### When to use - To confirm something that happened in the background (saved, copied, connected). - Messages that need an answer belong in a [Dialog](https://albakore.github.io/pyzed/library/confirm/). #### Usage ```python import pyzed as pz from pyzed import ui import threading class Notes(pz.App): def __init__(self): self.messages = [] def notify(self, title): self.messages.append(title) threading.Timer(3, pz.post, args=(("expire", title),)).start() # hide it after 3 s def update(self, message): if message[0] == "expire": self.messages.remove(message[1]) def view(self): items = [ui.toast(m, kind="success", on_dismiss=lambda m=m: self.messages.remove(m)) for m in self.messages] return ui.toasts(self.main_view(), items) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Kind ```python ui.toast("Update available", "Pyzed 0.5 is on PyPI.") ``` ```python ui.toast("Saved", "main.py was saved.", kind="success") ``` ```python ui.toast("Low disk space", "2 GB left.", kind="warning") ``` ```python ui.toast("Could not connect", "Check your network.", kind="error") ``` ##### Content ```python ui.toast("Copied to clipboard", kind="success") ``` ```python ui.toast("Update available", "Restart to install it.", actions=[ui.button("Restart", on_restart, size="sm")], on_dismiss=on_dismiss) ``` ```python ui.toast("Now playing", "Lo-fi beats", icon="music", width=280) ``` ##### States and events ```python ui.toast("Uploading", "notes.md", kind="info", progress=0.6, on_dismiss=on_close) ``` ```python ui.toast("Build failed", "Click to see the log", kind="error", on_press=on_press) ``` #### Events Toast has **2 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_dismiss` | `()` | Message or callable sent on close. | | `on_press` | `()` | Makes the card clickable. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Notes(pz.App): def __init__(self): self.messages = ["Saved"] self.opened = 0 def view(self): items = [ui.toast(m, kind="success", on_dismiss=lambda m=m: self.messages.remove(m), # its ✕ on_press=lambda: setattr(self, "opened", self.opened + 1)) # the card for m in self.messages] return ui.toasts(main_view(), items) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Dismiss: text: str class Notes(pz.App): messages = ["Saved"] def update(self, message): match message: case Dismiss(text): self.messages = [m for m in self.messages if m != text] def view(self): return ui.toasts(main_view(), [ui.toast(m, kind="success", on_dismiss=Dismiss(m)) for m in self.messages]) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: messages: tuple = ("Saved",) def view(state, set_state): close = lambda m: set_state(messages=tuple(x for x in state.messages if x != m)) return ui.toasts(main_view(), [ui.toast(m, kind="success", on_dismiss=lambda m=m: close(m)) for m in state.messages]) ``` #### Properties and API ##### `ui.toast` ```python toast( title, message=None, *, kind='info', icon=None, on_dismiss=None, actions=(), width=340, progress=None, on_press=None, theme=None, ) ``` A notification. | Property | Default | Description | | --- | --- | --- | | `title` | *required* | Title. | | `message` | `None` | Secondary text. | | `kind` | `"info"` | `"info"`, `"success"`, `"warning"` or `"error"`. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `actions` | `()` | Extra widgets (usually buttons) shown as actions. | | `width` | `340` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `progress` | `None` | 0 to 1: a thin bar at the bottom (time left, a download). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_dismiss`, `on_press` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#toast) ##### `ui.toasts` ```python toasts(base, items, *, spacing=8) ``` Shows `items` (usually `toast(...)`) stacked in the bottom-right corner over `base`. | Property | Default | Description | | --- | --- | --- | | `base` | *required* | The UI underneath. | | `items` | *required* | List of toasts. | | `spacing` | `8` | Space between children, in pixels. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#toasts) #### Related - [Callout](https://albakore.github.io/pyzed/library/callout/): An inline notice with a title, text and actions. - [Layer](https://albakore.github.io/pyzed/library/layer/): Draws an overlay over your view; clicking outside dismisses it. - [Alert](https://albakore.github.io/pyzed/library/alert/): A message with one button. ### Toggle group > An icon-only segmented control. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/toggle-group/ :::tip[In plain words] A row of icon buttons where only one can be on, like choosing left, center or right alignment. ::: A row of icon buttons where exactly one is selected, like text alignment in an editor. `options` are `(value, icon)` pairs and `on_select` receives the chosen value. `ui.toggle_group` · Category: [Actions](https://albakore.github.io/pyzed/library/#actions) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#toggle_group) **Code:** ```python pz.row([ ui.toggle_group([("left", "align-left"), ("center", "align-center"), ("right", "align-right")], "center", on_align), ui.toggle_group([("list", "list"), ("grid", "layout-grid")], "grid", on_layout), ], spacing=16) ``` #### When to use - For a small set of mutually exclusive modes that have clear icons. - With text labels, use [Segmented](https://albakore.github.io/pyzed/library/segmented/) instead. #### Usage ```python import pyzed as pz from pyzed import ui class Toolbar(pz.App): def __init__(self): self.align = "left" def view(self): return ui.toggle_group( [("left", "align-left"), ("center", "align-center"), ("right", "align-right")], self.align, lambda value: setattr(self, "align", value), ) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python ui.toggle_group([("list", "list"), ("grid", "layout-grid")], "list", on_select) ``` ```python ui.toggle_group([("left", "align-left"), ("center", "align-center"), ("right", "align-right")], "center", on_select) ``` ```python ui.toggle_group([("b", "bold"), ("i", "italic"), ("u", "underline"), ("s", "strikethrough")], "b", on_select) ``` ##### Selection ```python ui.toggle_group([("left", "align-left"), ("center", "align-center"), ("right", "align-right")], "left", on_select) ``` ```python ui.toggle_group([("left", "align-left"), ("center", "align-center"), ("right", "align-right")], "right", on_select) ``` ```python ui.toggle_group([("left", "align-left"), ("center", "align-center"), ("right", "align-right")], None, on_select) ``` ##### States and events A third item in an option adds a tooltip: `(value, icon, tooltip)`. ```python ui.toggle_group([("b", "bold"), ("i", "italic"), ("u", "underline")], {"b", "u"}, on_select, multiple=True) ``` ```python ui.toggle_group([("left", "align-left"), ("center", "align-center"), ("right", "align-right")], "left", on_select, disabled={"right"}) ``` #### Events Toggle group has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_select` | `(value)` | Callable that receives the chosen item. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Toolbar(pz.App): def __init__(self): self.align = "left" def set_align(self, value): # on_select gets the value of the pressed option self.align = value def view(self): return ui.toggle_group([("left", "align-left"), ("center", "align-center"), ("right", "align-right")], self.align, self.set_align) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Align: value: str class Toolbar(pz.App): align = "left" def update(self, message): match message: case Align(value): self.align = value def view(self): return ui.toggle_group([("left", "align-left"), ("center", "align-center")], self.align, Align) # the class builds the message from the value ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: align: str = "left" def view(state, set_state): return ui.toggle_group([("left", "align-left"), ("center", "align-center"), ("right", "align-right")], state.align, lambda value: set_state(align=value)) ``` #### Properties and API ##### `ui.toggle_group` ```python toggle_group( options, selected, on_select=None, *, disabled=False, multiple=False, theme=None, ) ``` An icon-only segmented control. | Property | Default | Description | | --- | --- | --- | | `options` | *required* | `(value, icon_name)` or `(value, icon_name, tooltip)`. | | `selected` | *required* | Current value (a collection with `multiple`). | | `disabled` | `False` | `True`, or the values to disable. | | `multiple` | `False` | Each button toggles its value on or off. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_select` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#toggle_group) #### Related - [Segmented](https://albakore.github.io/pyzed/library/segmented/): A group of mutually exclusive text buttons. - [Radio group](https://albakore.github.io/pyzed/library/radio-group/): Mutually exclusive options as radio buttons. - [Icon button](https://albakore.github.io/pyzed/library/icon-button/): A square button with just an icon and an optional tooltip. ### Tool call > One step of an AI agent: what it did, its result, and Allow or Reject. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/tool-call/ :::tip[In plain words] One thing an AI assistant did, like reading or changing a file. Click it to see the details; if it needs your permission, it asks with Allow and Reject buttons. ::: `ui.ToolCall` is a component for one action of an AI agent (reading a file, editing it, running a command), drawn like in Zed: a line with its status, the `title` and what it works on (`detail`), and a click unfolds the `input` and the `output` (plus any `images`). Edits, commands (`kind` `edit`, `delete`, `move` or `execute`) and calls that wait are cards instead. `diffs` show the edits it made as colored diffs, and while it runs `progress` shows the last lines a command printed. While `status` is `"waiting"` it asks right on the card: Always allow, Allow or Reject, reported through `on_allow`, `on_allow_always` and `on_deny`. The component remembers whether it is unfolded; your app only keeps the data. `ui.ToolCall` · Category: [AI agents](https://albakore.github.io/pyzed/library/#ai-agents) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#toolcall) **Code:** ```python pz.column([ ui.ToolCall(title="Read file", detail="app/storage.py", kind="read", output="def save(path): ..."), ui.ToolCall(title="Search", detail="def save", kind="search", output="app/storage.py:12"), ui.ToolCall(title="Edit file", detail="app/storage.py", kind="edit", status="waiting", diffs=[{"path": "app/storage.py", "old": "def save(path):\n write(path)\n", "new": "def save(path, data):\n write(path, data)\n"}], on_allow=on_allow, on_allow_always=on_allow_always, on_deny=on_deny), ui.ToolCall(title="Run", detail="pytest -q", kind="execute", status="running", progress="collected 24 items\n........................"), ], spacing=4, width=560) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - In an agent's chat, one per step the agent takes. - With `status="waiting"`, to ask before a risky step such as writing files or running a command. - For an edit on its own, outside a tool call, use [Diff view](https://albakore.github.io/pyzed/library/diff-view/). #### Usage ```python import pyzed as pz from pyzed import ui class Chat(pz.App): def __init__(self): self.status = "waiting" def answer(self, allowed): self.status = "done" if allowed else "rejected" def view(self): return ui.ToolCall(title="Run", detail="pytest -q", kind="execute", status=self.status, input={"command": "pytest -q"}, output="24 passed", on_allow=lambda e: self.answer(True), on_deny=lambda e: self.answer(False)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### State Pending and running show a spinner, waiting asks with Always allow, Allow and Reject, failed and rejected say so in red. ```python pz.container(ui.ToolCall(title="Edit file", detail="app.py", kind="edit", status="pending"), width=360) ``` ```python pz.container(ui.ToolCall(title="Edit file", detail="app.py", kind="edit", status="running"), width=360) ``` ```python pz.container(ui.ToolCall(title="Edit file", detail="app.py", kind="edit", status="done"), width=360) ``` ```python pz.container(ui.ToolCall(title="Edit file", detail="app.py", kind="edit", status="waiting", on_allow=on_allow, on_allow_always=on_allow_always, on_deny=on_deny), width=360) ``` ```python pz.container(ui.ToolCall(title="Edit file", detail="app.py", kind="edit", status="failed"), width=360) ``` ```python pz.container(ui.ToolCall(title="Edit file", detail="app.py", kind="edit", status="rejected"), width=360) ``` ##### Kind The kind picks the icon of a finished call. ```python pz.container(ui.ToolCall(title="Read file", detail="app.py", kind="read"), width=300) ``` ```python pz.container(ui.ToolCall(title="Edit file", detail="app.py", kind="edit"), width=300) ``` ```python pz.container(ui.ToolCall(title="Delete file", detail="old.py", kind="delete"), width=300) ``` ```python pz.container(ui.ToolCall(title="Move file", detail="a.py → b.py", kind="move"), width=300) ``` ```python pz.container(ui.ToolCall(title="Search", detail="def save", kind="search"), width=300) ``` ```python pz.container(ui.ToolCall(title="Run", detail="pytest -q", kind="execute"), width=300) ``` ```python pz.container(ui.ToolCall(title="Think", kind="think"), width=300) ``` ```python pz.container(ui.ToolCall(title="Fetch", detail="https://example.com", kind="fetch"), width=300) ``` ```python pz.container(ui.ToolCall(title="Switch mode", detail="plan", kind="switch_mode"), width=300) ``` ```python pz.container(ui.ToolCall(title="Tool", detail="custom", kind="other"), width=300) ``` ##### Content Unfolded ones are drawn as they look after a click on the header. ```python pz.container(ui.ToolCall(title="Run", detail="pytest -q", kind="execute", status="running", progress="collected 24 items\n............\n............"), width=360) ``` ```python pz.container(ui.ToolCall(title="Edit file", detail="app.py", kind="edit", status="running", diffs=[{"path": "app.py", "old": "x = 1\ny = 2\n", "new": "x = 10\ny = 2\n"}]), width=360) ``` ```python pz.container(ui.ToolCall(title="Run", detail="rm -rf build", kind="execute", status="waiting", allow_always=False, on_allow=on_allow, on_deny=on_deny), width=360) ``` ```python pz.container(ui.ToolCall(title="Read file", detail="app.py", kind="read", input={"path": "app.py"}, output="import pyzed as pz\n\npz.run(App)"), width=360) ``` ```python pz.container(ui.ToolCall(title="Edit file", detail="app.py", kind="edit", diffs=[{"path": "app.py", "old": "x = 1\ny = 2\n", "new": "x = 10\ny = 2\n"}]), width=360) ``` #### Events Tool call has **3 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data. | Event | Handler gets | When | | --- | --- | --- | | `on_allow` | `(event)` | Allow was pressed. | | `on_allow_always` | `(event)` | Always allow was pressed. | | `on_deny` | `(event)` | Reject was pressed. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Chat(pz.App): def __init__(self): self.status = "waiting" def answer(self, status): self.status = status def view(self): # a pz.Component: handlers get a pz.Event return ui.ToolCall(title="Run", detail="pytest -q", kind="execute", status=self.status, input={"command": "pytest -q"}, on_allow=lambda e: self.answer("done"), on_allow_always=lambda e: self.answer("done"), on_deny=lambda e: self.answer("rejected")) ``` **Declarative:** ```python class Chat(pz.App): status = "waiting" def update(self, message): match message: case "allow": self.status = "done" case "deny": self.status = "rejected" def view(self): return ui.ToolCall(title="Run", detail="pytest -q", kind="execute", status=self.status, on_allow="allow", on_deny="deny") # messages work for components too ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: status: str = "waiting" def view(state, set_state): return ui.ToolCall(title="Run", detail="pytest -q", kind="execute", status=state.status, on_allow=lambda e: set_state(status="done"), on_deny=lambda e: set_state(status="rejected")) ``` #### Tips :::tip `status` is yours: set it from what the agent reports (`pending`, then `running`, then `done` or `failed`; `rejected` after a Reject). `kind` only picks the icon: `read`, `edit`, `delete`, `move`, `search`, `execute`, `think`, `fetch`, `switch_mode` or `other`. The header only unfolds when there is something to show (`input`, `output`, `images` or `diffs`). ::: #### Properties and API ##### `ui.ToolCall` ```python class ToolCall ``` A component for one action of an AI agent, drawn like in Zed's Agent panel: a line with its icon, what it does and where (it unfolds to show the input and the output), or a card for edits and commands, with the diff or the output. While `status` is `"waiting"` it asks right on the card: Always allow, Allow or Reject. See [AI agents](https://albakore.github.io/pyzed/editor/ai-agents/). | Property | Default | Description | | --- | --- | --- | | `title` | `""` | What it does ("Edit file"). | | `detail` | `""` | What it works on, in a monospace font. | | `kind` | `""` | ACP's kind: `read`, `edit`, `delete`, `move`, `search`, `execute`, `think`, `fetch` or `other` (its icon). | | `status` | `"done"` | `pending`, `running`, `waiting`, `done`, `failed` or `rejected`. | | `input` | `None` | The arguments (a dict or text). | | `output` | `None` | The answer (text or a dict). | | `images` | `None` | PNG bytes shown under the output. | | `diffs` | `None` | The edits it made: `{"path", "old", "new"}` dicts, shown as colored diffs (see `ui.diff_view`). | | `progress` | `""` | What it printed so far (a command's output); its last lines show under the header while it runs. | | `allow_always` | `True` | Shows Always allow. | | `theme` | `None` | Theme. | Events: `on_allow`, `on_allow_always`, `on_deny` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#toolcall) #### Related - [Diff view](https://albakore.github.io/pyzed/library/diff-view/): An edit as colored lines: added in green, removed in red. - [Plan](https://albakore.github.io/pyzed/library/plan/): An agent's plan as a checklist that folds. - [Edits bar](https://albakore.github.io/pyzed/library/edits-bar/): The files an agent changed, with Keep all and Reject all. - [Context meter](https://albakore.github.io/pyzed/library/context-meter/): How full a model's context window is: a ring and `48k / 200k`. ### Toolbar > The bar under the tabs: breadcrumbs and buffer actions. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/toolbar/ :::tip[In plain words] A thin bar with the actions of what you are looking at. ::: The bar below the tabs of a code editor: widgets at the `start` (usually breadcrumbs) and at the `end` (buffer actions). `ui.toolbar` · Category: [Navigation](https://albakore.github.io/pyzed/library/#navigation) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#toolbar) **Code:** ```python ui.toolbar( [ui.breadcrumbs([("file-code", "src"), "main.rs", "fn main"])], [ui.icon_button("search", on_search, size="sm"), ui.icon_button("sparkles", on_assist, size="sm")], ) ``` #### When to use - Between the tab bar and the editor, or at the top of any content view. #### Usage ```python from pyzed import ui ui.toolbar( [ui.breadcrumbs([("file-code", "src"), "main.rs", "fn main"])], [ui.icon_button("search", on_search, size="sm"), ui.icon_button("sparkles", on_assist, size="sm")], ) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Content ```python pz.container(ui.toolbar([ui.breadcrumbs(["src", "main.rs"])]), width=400) ``` ```python pz.container(ui.toolbar([], [ui.icon_button("search", on_search, size="sm"), ui.icon_button("sparkles", on_assist, size="sm")]), width=400) ``` ```python pz.container(ui.toolbar([ui.label("Preview")], [ui.button("Publish", on_publish, size="sm", variant="solid")], height=40), width=400) ``` ##### States and events ```python pz.container(ui.toolbar([ui.breadcrumbs(["src", "app.py"])], [ui.icon_button("play", on_press)], center=ui.muted("Running…", size="sm")), width=440) ``` #### Events Toolbar has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Properties and API ##### `ui.toolbar` ```python toolbar(start=(), end=(), *, center=None, height=32, theme=None) ``` The bar below the tabs: breadcrumbs on the left and buffer actions on the right. | Property | Default | Description | | --- | --- | --- | | `start` | `()` | Widgets at the start (left). | | `end` | `()` | Widgets at the end (right). | | `center` | `None` | Kept in the middle of the bar whatever the widths of both sides. | | `height` | `32` | Height. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#toolbar) #### Related - [Tab bar](https://albakore.github.io/pyzed/library/tab-bar/): Editor tabs with icons, dirty dots and close buttons. - [Breadcrumbs](https://albakore.github.io/pyzed/library/breadcrumbs/): `src › main.rs › fn main`, optionally clickable. - [Icon button](https://albakore.github.io/pyzed/library/icon-button/): A square button with just an icon and an optional tooltip. ### Tooltip > A hint shown on hover, optionally with its shortcut. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/tooltip/ :::tip[In plain words] A little box with a hint that appears when you rest the mouse on something. ::: Wraps any widget and shows a small themed box next to it while the mouse is over it. `keys=` adds the shortcut and `position` is `"top"`, `"bottom"` (default), `"left"` or `"right"`. `pz.tooltip` is the unstyled base version. `ui.tooltip` · Category: [Display](https://albakore.github.io/pyzed/library/#display) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#tooltip) **Code:** ```python pz.row([ ui.tooltip(ui.icon_button("save", on_save), "Save", keys="ctrl-s"), ui.icon_button("settings", on_settings, tooltip="Settings"), ], spacing=8) ``` #### When to use - On icon buttons and compact controls whose meaning is not obvious. - Don't hide essential information in a tooltip: it is invisible on touch and keyboard use. #### Usage ```python import pyzed as pz from pyzed import ui pz.row([ ui.tooltip(ui.icon_button("save", on_save), "Save", keys="ctrl-s"), ui.icon_button("settings", on_settings, tooltip="Settings"), ], spacing=8) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Position Drawn as the pointer shows it: tooltips only open on hover. ```python ui.tooltip(ui.icon_button("save", on_save), "Save") ``` ```python ui.tooltip(ui.icon_button("save", on_save), "Save", position="top") ``` ```python ui.tooltip(ui.icon_button("save", on_save), "Save", position="right") ``` ```python ui.tooltip(ui.icon_button("save", on_save), "Save", position="left") ``` ##### Content Drawn as the pointer shows it: tooltips only open on hover. ```python ui.tooltip(ui.button("Save", on_save), "Save the file", keys="ctrl-s") ``` ```python ui.icon_button("settings", on_settings, tooltip="Settings") ``` #### Events Tooltip has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). #### Tips :::tip Tooltips only appear on hover, so the preview shows the buttons. `ui.icon_button(..., tooltip="Text")` is a shortcut for wrapping it in `ui.tooltip`. ::: #### Properties and API ##### `ui.tooltip` ```python tooltip(content, text, *, keys=None, position='bottom', theme=None) ``` Wraps `content` with a themed tooltip, optionally with its shortcut. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `text` | *required* | Tooltip text. | | `keys` | `None` | Shortcut shown at the end, written as a string: `"ctrl-s"`, `"cmd-k cmd-s"`. | | `position` | `"bottom"` | `"top"`, `"bottom"`, `"left"`, `"right"` or `"cursor"`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#tooltip) ##### `pz.tooltip` ```python tooltip( content, tip, *, position='bottom', gap=4.0, bg=None, color=None, border_color=None, border_width=0.0, radius=None, shadow=None, ) ``` Shows `tip` next to `content` on hover. `ui.tooltip` adds the theme's style. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | Content: a `Widget`, a string or a number (converted to text). | | `tip` | *required* | Tooltip content. | | `position` | `"bottom"` | `"top"`, `"bottom"`, `"left"`, `"right"` or `"cursor"`. | | `gap` | `4.0` | Distance from the content. | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `color` | `None` | Text or icon color. | | `border_color` | `None` | Border color. | | `border_width` | `0.0` | Border width in pixels. | | `radius` | `None` | Corner radius: a number or `(top_left, top_right, bottom_right, bottom_left)`. | | `shadow` | `None` | Shadow: `(color, (dx, dy), blur)`. | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#tooltip) #### Related - [Icon button](https://albakore.github.io/pyzed/library/icon-button/): A square button with just an icon and an optional tooltip. - [Kbd](https://albakore.github.io/pyzed/library/kbd/): Keyboard shortcuts drawn as keys, with symbols on macOS. - [Popover](https://albakore.github.io/pyzed/library/popover/): Floating content at a point: context menus, color pickers. ### Tree > A collapsible file tree with icons and git colors. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/tree/ :::tip[In plain words] A list of folders you can open and close, like the files of a project. ::: A project panel: collapsible folders, an icon per file type and git status colors. `TreeNode.from_paths(paths, status=...)` builds the nodes, puts folders first and propagates the git status to the folders that contain changes. Each node's id is its path; you own the `expanded` set and the `selected` id. `ui.tree` · Category: [Lists and menus](https://albakore.github.io/pyzed/library/#lists-and-menus) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#tree) **Code:** ```python nodes = ui.TreeNode.from_paths( ["src/main.rs", "src/app.rs", "src/ui/button.rs", "src/ui/mod.rs", "tests/app.rs", "Cargo.toml"], status={"src/app.rs": "modified", "src/ui/button.rs": "created"}, ) pz.container(ui.tree(nodes, expanded={"src", "src/ui"}, selected="src/app.rs", on_toggle=on_toggle, on_select=on_select), width=280) ``` #### When to use - For files and any hierarchy: outlines, categories, settings sections. - `status` is `"modified"`, `"created"`, `"deleted"`, `"conflict"` or `"ignored"`. #### Usage ```python import pyzed as pz from pyzed import ui class Explorer(pz.App): def __init__(self): self.nodes = ui.TreeNode.from_paths(["src/main.rs", "src/app.rs", "Cargo.toml"]) self.expanded = {"src"} self.selected = None def toggle(self, folder): self.expanded ^= {folder} def view(self): return ui.tree(self.nodes, expanded=self.expanded, selected=self.selected, on_toggle=self.toggle, on_select=lambda path: setattr(self, "selected", path)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Expanded ```python nodes = ui.TreeNode.from_paths(["src/main.rs", "src/app.rs", "src/ui/mod.rs", "src/ui/button.rs", "Cargo.toml"]) pz.container(ui.tree(nodes, expanded=set()), width=240) ``` ```python nodes = ui.TreeNode.from_paths(["src/main.rs", "src/app.rs", "src/ui/mod.rs", "src/ui/button.rs", "Cargo.toml"]) pz.container(ui.tree(nodes, expanded={"src"}), width=240) ``` ```python nodes = ui.TreeNode.from_paths(["src/main.rs", "src/app.rs", "src/ui/mod.rs", "src/ui/button.rs", "Cargo.toml"]) pz.container(ui.tree(nodes, expanded={"src", "src/ui"}, selected="src/ui/button.rs"), width=240) ``` ##### Git status ```python nodes = ui.TreeNode.from_paths(["src/app.rs", "src/new.rs", "src/old.rs", "build.log"], status={"src/app.rs": "modified", "src/new.rs": "created", "src/old.rs": "deleted", "build.log": "ignored"}) pz.container(ui.tree(nodes, expanded={"src"}), width=240) ``` ```python nodes = ui.TreeNode.from_paths(["merge.py", "ok.py"], status={"merge.py": "conflict"}) pz.container(ui.tree(nodes, expanded=set()), width=240) ``` ##### Density ```python nodes = ui.TreeNode.from_paths(["src/main.rs", "src/app.rs", "src/ui/mod.rs", "src/ui/button.rs", "Cargo.toml"]) pz.container(ui.tree(nodes, expanded={"src", "src/ui"}, item_height=20, indent=10), width=240) ``` ```python nodes = ui.TreeNode.from_paths(["src/main.rs", "src/app.rs", "src/ui/mod.rs", "src/ui/button.rs", "Cargo.toml"]) pz.container(ui.tree(nodes, expanded={"src"}, item_height=30, indent=20), width=240) ``` ##### States and events `on_open(id)` runs on a double click of a file and `on_context(id)` on a right click. ```python pz.container(ui.tree(ui.TreeNode.from_paths(["src/app.py", "src/ui.py", "README.md"]), expanded={"src"}, selected={"src/app.py", "README.md"}, focused="src/ui.py", on_open=on_open, on_context=on_context), width=300) ``` #### Examples ##### A real folder Build the paths with `pathlib` and pass them to `from_paths`. ```python from pathlib import Path root = Path(".") paths = [p.relative_to(root).as_posix() for p in root.rglob("*") if p.is_file() and ".git" not in p.parts] nodes = ui.TreeNode.from_paths(paths) ``` ##### Nodes by hand Folders are nodes with `children`. **Code:** ```python nodes = [ ui.TreeNode("Inbox", children=[ui.TreeNode("Welcome", id="inbox/1", icon="mail")], id="inbox"), ui.TreeNode("Archive", children=[], id="archive"), ui.TreeNode("Notes.md", id="notes", icon="notebook-pen"), ] pz.container(ui.tree(nodes, expanded={"inbox"}, selected="inbox/1"), width=260) ``` #### Events Tree has **4 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_toggle` | `(id)` | Called with the id of the clicked folder. | | `on_select` | `(id)` | Called with the id of the clicked file. | | `on_open` | `(id)` | Called with the id of a file that is double-clicked. | | `on_context` | `(id)` | Called with the id of a row that is right-clicked (show a `ui.menu` there). | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Explorer(pz.App): def __init__(self): self.nodes = ui.TreeNode.from_paths(["src/main.rs", "src/app.rs", "Cargo.toml"]) self.expanded = {"src"} self.selected = None def toggle(self, folder): # on_toggle: the folder's id (its path) self.expanded ^= {folder} def view(self): return ui.tree(self.nodes, expanded=self.expanded, selected=self.selected, on_toggle=self.toggle, on_select=lambda path: setattr(self, "selected", path), # click on a file on_open=lambda path: print("open", path), # double click on_context=lambda path: print("menu for", path)) # right click ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Toggle: folder: str @dataclass class Select: path: str class Explorer(pz.App): nodes = ui.TreeNode.from_paths(["src/main.rs", "src/app.rs", "Cargo.toml"]) expanded = frozenset({"src"}) selected = None def update(self, message): match message: case Toggle(folder): self.expanded = self.expanded ^ {folder} case Select(path): self.selected = path def view(self): return ui.tree(self.nodes, expanded=self.expanded, selected=self.selected, on_toggle=Toggle, on_select=Select) ``` **Functional:** ```python from dataclasses import dataclass NODES = ui.TreeNode.from_paths(["src/main.rs", "src/app.rs", "Cargo.toml"]) @dataclass(frozen=True) class State: expanded: frozenset = frozenset({"src"}) selected: str = "" def view(state, set_state): return ui.tree(NODES, expanded=state.expanded, selected=state.selected, on_toggle=lambda folder: set_state(expanded=state.expanded ^ {folder}), on_select=lambda path: set_state(selected=path)) ``` #### Properties and API ##### `ui.tree` ```python tree( nodes, *, expanded, selected=None, on_toggle=None, on_select=None, on_open=None, on_context=None, focused=None, indent=14, item_height=24, theme=None, ) ``` A collapsible file tree, like a code editor's project panel. | Property | Default | Description | | --- | --- | --- | | `nodes` | *required* | List of `TreeNode`. | | `expanded` | *required* | Set of open folder ids. | | `selected` | `None` | One id or a collection of ids (multiple selection). | | `focused` | `None` | Outlines the row the keyboard is on. | | `indent` | `14` | Left indentation, in pixels. | | `item_height` | `24` | Height of each row. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_toggle`, `on_select`, `on_open`, `on_context` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#tree) ##### `ui.TreeNode` ```python @dataclass class TreeNode(name, children=None, id=None, status=None, icon=None, icon_color=None) ``` A file or folder for `ui.tree`. Folders have `children` (a list). `status` is `"modified"`, `"created"`, `"deleted"`, `"conflict"` or `"ignored"`. `TreeNode.from_paths(paths, status=None)` builds the tree from paths like `"src/main.rs"`, with folders first and the git status propagated to folders. | Property | Default | Description | | --- | --- | --- | | `name` | *required* | Display name. | | `children` | `None` | Children (`None` for a file). | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `status` | `None` | Git status. | | `icon` | `None` | Name of a Lucide icon (`pyzed icons` lists them). | | `icon_color` | `None` | Icon color: a theme token or a hex color. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#treenode) #### Related - [List item](https://albakore.github.io/pyzed/library/list-item/): A list row with icon, text and an end slot. - [Panel](https://albakore.github.io/pyzed/library/panel/): A dockable, resizable side panel. - [Workspace](https://albakore.github.io/pyzed/library/workspace/): The layout of an editor-style window: title bar, docks, center, status bar. ### Unsaved changes > “Save your changes before closing?”. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/unsaved-changes/ :::tip[In plain words] The “Save your changes before closing?” question. ::: “Save your changes to *name* before closing?” with Don't save, Cancel and Save. `ui.unsaved_changes` · Category: [Dialogs](https://albakore.github.io/pyzed/library/#dialogs) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#unsaved_changes) **Code:** ```python ui.dialog_layer(main_view(), ui.unsaved_changes("notes.py", on_save, on_discard, on_cancel)) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - When closing a tab or a window with unsaved edits. #### Usage ```python from pyzed import ui ui.dialog_layer(main_view(), ui.unsaved_changes("notes.py", on_save, on_discard, on_cancel)) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python ui.unsaved_changes("notes.py", on_save, on_discard, on_cancel) ``` ```python ui.unsaved_changes("report.pzform", on_save, on_discard, on_cancel, width=360) ``` #### Events Unsaved changes has **3 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_save` | `()` | Save. | | `on_discard` | `()` | Don't save. | | `on_cancel` | `()` | Cancel. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Notes(pz.App): def __init__(self): self.closing = True def save(self): self.closing = False # write the file, then close def view(self): dialog = ui.unsaved_changes("notes.py", self.save, lambda: setattr(self, "closing", False), # on_discard lambda: setattr(self, "closing", False)) # on_cancel return ui.dialog_layer(main_view(), dialog if self.closing else None) ``` **Declarative:** ```python class Notes(pz.App): closing = True def update(self, message): match message: case "save" | "discard": self.closing = False case "cancel": self.closing = False def view(self): dialog = ui.unsaved_changes("notes.py", "save", "discard", "cancel") return ui.dialog_layer(main_view(), dialog if self.closing else None) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: closing: bool = True saved: bool = False def view(state, set_state): dialog = ui.unsaved_changes("notes.py", lambda: set_state(saved=True, closing=False), lambda: set_state(closing=False), lambda: set_state(closing=False)) return ui.dialog_layer(main_view(), dialog if state.closing else None) ``` #### Properties and API ##### `ui.unsaved_changes` ```python unsaved_changes(name, on_save, on_discard, on_cancel, *, width=440, theme=None) ``` "Save your changes to *name* before closing?" with Don't save, Cancel and Save. | Property | Default | Description | | --- | --- | --- | | `name` | *required* | File or document name. | | `width` | `440` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_save`, `on_discard`, `on_cancel` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#unsaved_changes) #### Related - [Confirm](https://albakore.github.io/pyzed/library/confirm/): A yes/no question, red for destructive actions. - [Choice](https://albakore.github.io/pyzed/library/choice/): A message with your own buttons. - [Tab bar](https://albakore.github.io/pyzed/library/tab-bar/): Editor tabs with icons, dirty dots and close buttons. ### Virtual list > A list that only builds the rows in view, for millions of items. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/virtual-list/ :::tip[In plain words] A list that stays fast even with millions of rows, because it only draws what you see. ::: A scrolling list for thousands or millions of items. Only the rows in view are built: `render(item)` is called when an item scrolls into view, so the list costs the same whatever its length. Every row has the same `item_height`. `pz.virtual_column` is the building block underneath (rows by index, inside any `scrollable`), and [Table](https://albakore.github.io/pyzed/library/table/) uses it for its rows too. `ui.virtual_list` · Category: [Lists and menus](https://albakore.github.io/pyzed/library/#lists-and-menus) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#virtual_list) **Code:** ```python files = [f"src/module_{i:06}.py" for i in range(1_000_000)] pz.container(ui.virtual_list( files, lambda f: ui.list_item(f, icon="file-code", selected=f.endswith("02.py")), height=240, ), width=420) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For logs, search results, file lists or any list that can grow past a few hundred rows. - For short lists, a `pz.column` of [List items](https://albakore.github.io/pyzed/library/list-item/) is simpler. #### Usage ```python import pyzed as pz from pyzed import ui class Logs(pz.App): def __init__(self): self.lines = [f"[{i:06}] request handled" for i in range(500_000)] def view(self): return ui.virtual_list(self.lines, lambda line: pz.text(line, font="mono", size=12), item_height=20, id="logs") ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Options ```python pz.container(ui.virtual_list([f"row {i:,}" for i in range(1_000_000)], lambda r: ui.list_item(r, icon="file"), height=150), width=260) ``` ```python pz.container(ui.virtual_list([f"[{i:06}] request handled" for i in range(100_000)], lambda line: pz.text(line, font="mono", size=12), item_height=20, height=150), width=260) ``` ```python pz.container(ui.virtual_list(list(range(10_000)), lambda i: ui.card(ui.label(f"Card {i}"), padding=8), item_height=40, spacing=6, height=150), width=260) ``` #### Examples ##### Rows by index `pz.virtual_column(count, item, item_height=...)` calls `item(index)`, handy when the rows come from an array, a database cursor or a computed value. Scroll it like any `scrollable`: row `i` starts at `i * (item_height + spacing)`. **Code:** ```python pz.container(pz.scrollable( pz.virtual_column(10_000_000, lambda i: pz.text(f"{i:>10,} {i * i:>22,}", font="mono", size=12), item_height=22), height=150, ), width=420) ``` #### Events Virtual list has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_scroll` | `(info)` | Callable that receives the scroll viewport, as in `pz.scrollable`. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Logs(pz.App): def __init__(self): self.lines = [f"[{i:06}] request handled" for i in range(100_000)] self.top = 0 def scrolled(self, info): # on_scroll: offsets and sizes of the viewport self.top = int(info["y"] // 20) def view(self): return pz.column([ ui.label(f"Line {self.top + 1} of {len(self.lines)}"), ui.virtual_list(self.lines, lambda line: pz.text(line, font="mono", size=12), item_height=20, height=200, on_scroll=self.scrolled), ], spacing=6) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Scrolled: info: dict class Logs(pz.App): lines = [f"[{i:06}] request handled" for i in range(100_000)] top = 0 def update(self, message): match message: case Scrolled(info): self.top = int(info["y"] // 20) def view(self): return ui.virtual_list(self.lines, lambda line: pz.text(line, size=12), item_height=20, height=200, on_scroll=Scrolled) ``` **Functional:** ```python from dataclasses import dataclass LINES = [f"[{i:06}] request handled" for i in range(100_000)] @dataclass(frozen=True) class State: top: int = 0 def view(state, set_state): return pz.column([ ui.label(f"Line {state.top + 1}"), ui.virtual_list(LINES, lambda line: pz.text(line, size=12), item_height=20, height=200, on_scroll=lambda info: set_state(top=int(info["y"] // 20))), ], spacing=6) ``` #### Tips :::tip - Rows are built again when they scroll back into view, so keep `render` cheap or wrap it in `@pz.memo`. - `items` should be a list or another sequence: other iterables are copied into a list on every `view()`. ::: #### Properties and API ##### `ui.virtual_list` ```python virtual_list( items, render, *, item_height=26, spacing=0, width='fill', height='fill', padding=None, overscan=4, id=None, on_scroll=None, theme=None, ) ``` A scrolling list that only builds the rows in view, for thousands or millions of items. `render(item)` returns the widget for one item and is called when it scrolls into view. Every row has the same height. | Property | Default | Description | | --- | --- | --- | | `items` | *required* | The items: a list or any sequence (other iterables are turned into a list). | | `render` | *required* | Function that receives an item and returns its widget. | | `item_height` | `26` | Height of every row, in pixels. | | `spacing` | `0` | Space between children, in pixels. | | `width` | `"fill"` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `"fill"` | Height: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `padding` | `None` | Inner padding: `8`, `(vertical, horizontal)` or `(top, right, bottom, left)`. | | `overscan` | `4` | Extra rows built above and below the visible ones. | | `id` | `None` | Stable identifier used to focus or scroll it with a `Command`. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_scroll` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#virtual_list) ##### `pz.virtual_column` ```python virtual_column(count, item, *, item_height, spacing=0.0, overscan=4, width=None) ``` A column of `count` rows of the same height that only builds the rows in view: `item(index)` is called when row `index` scrolls into view, and rows that leave it are dropped. A column of a million rows costs the same as one of fifty. Put it in a `scrollable` (it virtualizes against the visible area of the closest one, or the window). | Property | Default | Description | | --- | --- | --- | | `count` | *required* | Number of rows. | | `item` | *required* | Function that receives a row index and returns its widget. | | `item_height` | *required* | Height of every row, in pixels. | | `spacing` | `0.0` | Space between rows, in pixels. | | `overscan` | `4` | Extra rows built above and below the visible ones, so fast scrolling shows no gaps. | | `width` | `None` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#virtual_column) #### Related - [List item](https://albakore.github.io/pyzed/library/list-item/): A list row with icon, text and an end slot. - [Table](https://albakore.github.io/pyzed/library/table/): A data table with a fixed header, sorting and selection. ### Window frame > Your own title bar, window buttons and menus. A native Pyzed component for Python desktop GUIs, with a live preview, code examples and its API. Source: https://albakore.github.io/pyzed/library/window-frame/ :::tip[In plain words] Draws the window's own top bar, with its menus and minimize / maximize / close buttons. ::: Draws the whole frame of a window opened without system decorations (`frame = "custom"`): a title bar that moves the window (double click maximizes), the minimize, maximize and close buttons in the style of a platform, menus on the left (`ui.Menu`) and borders that resize the window. `ui.window_title_bar` is the bar alone, `ui.window_controls` the three buttons and `ui.system_platform()` says which style this system uses. `ui.window_frame` · Category: [Workspace](https://albakore.github.io/pyzed/library/#workspace) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#window_frame) **Code:** ```python ui.window_frame( ui.editor("frame-main", "import pyzed as pz\n\npz.run(App)\n", path="main.py"), title="notes.py", menus=[ui.Menu("File", [ui.MenuItem("Open…", on_open, keys="ctrl-o")]), ui.Menu("Edit", [ui.MenuItem("Undo", on_undo, keys="ctrl-z")])], start=[ui.title_button("pyzed", on_projects, chevron=True)], style="windows", ) ``` :::note[New] This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues). ::: #### When to use - For apps that want a modern editor-like window: menus and pickers in the title bar instead of the system's frame. See [Window frames](https://albakore.github.io/pyzed/guides/windows/#window-frames-your-own-title-bar). - With no callbacks, `ui.window_title_bar` and `ui.window_controls` only show: use them to preview a window in the frame of each platform. #### Usage ```python import pyzed as pz from pyzed import ui class Notes(pz.App): title = "Notes" frame = "custom" # or "macos", "windows", "gnome", "ubuntu", "kde" def view(self): return ui.window_frame( self.editor(), menus=[ui.Menu("File", [ui.MenuItem("Open…", self.open, keys="ctrl-o"), ui.SEPARATOR, ui.MenuItem("Quit", self.close)])], start=[ui.title_button("pyzed", chevron=True)], end=[ui.button("Run", self.run, icon="play", size="sm")], ) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Platform style ```python pz.container(ui.window_title_bar("notes.py", style="windows"), width=420) ``` ```python pz.container(ui.window_title_bar("notes.py", style="macos"), width=420) ``` ```python pz.container(ui.window_title_bar("notes.py", style="gnome"), width=420) ``` ```python pz.container(ui.window_title_bar("notes.py", style="kde"), width=420) ``` ```python pz.container(ui.window_title_bar("notes.py", style="ubuntu"), width=420) ``` ##### State ```python pz.container(ui.window_title_bar("notes.py", style="windows", focused=False), width=420) ``` ```python ui.window_controls("windows", maximized=True) ``` ```python ui.window_controls("macos") ``` #### Events Window frame has **5 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Of | Handler gets | When | | --- | --- | --- | --- | | `on_drag` | `ui.window_title_bar` | `()` | Called when the empty part of the bar is dragged (return `Command.drag_window()`). | | `on_minimize` | `ui.window_title_bar`, `ui.window_controls` | `()` | Minimize button. | | `on_maximize` | `ui.window_title_bar`, `ui.window_controls` | `()` | Maximize button and double click on the bar. | | `on_close` | `ui.window_title_bar`, `ui.window_controls` | `()` | Close button. | | `on_menu` | `ui.window_title_bar` | `()` | Right click on the bar. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Notes(pz.App): frame = "custom" # Pyzed draws the title bar def view(self): bar = ui.window_title_bar( "notes.py", on_drag=lambda: self.drag(), # the empty part of the bar on_minimize=lambda: self.minimize(), on_maximize=lambda: self.toggle_maximize(), # also a double click on the bar on_close=lambda: self.close(), on_menu=lambda: print("window menu"), # right click on the bar maximized=self.window_maximized, ) return pz.column([bar, main_view()]) ``` **Declarative:** ```python class Notes(pz.App): frame = "custom" def update(self, message): # the commands are returned from update match message: case "drag": return self.drag() case "minimize": return self.minimize() case "maximize": return self.toggle_maximize() case "close": return self.close() def view(self): return pz.column([ui.window_title_bar("notes.py", on_drag="drag", on_minimize="minimize", on_maximize="maximize", on_close="close"), main_view()]) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: title: str = "notes.py" def view(state, set_state): # A handler can return a command: Pyzed runs it. return pz.column([ui.window_title_bar(state.title, on_drag=lambda: pz.Command.drag_window(), on_close=lambda: pz.Command.exit()), main_view()]) ``` #### Tips :::tip With only menus, define `frame_menus()` on the window and skip `ui.window_frame`: the runtime frames the view for you. `style` defaults to the window's `frame`, or this system's style. ::: #### Properties and API ##### `ui.window_frame` ```python window_frame( content, *, title=None, menus=None, menu_button=True, start=(), center=None, end=(), style=None, window=None, height=None, resize_border=6.0, resize_edges=True, bg=None, theme=None, ) ``` The whole frame of a window opened with `frame="custom"`: a title bar that moves the window (double click maximizes, right click opens the system menu on Windows), the minimize, maximize and close buttons in the style of a platform, menus on the left, and borders that resize the window. | Property | Default | Description | | --- | --- | --- | | `content` | *required* | The window's content, under the title bar. | | `title` | `None` | Title shown in the bar. By default the window's `title`. | | `menus` | `None` | Menus on the left of the bar: a list of `ui.Menu`. | | `menu_button` | `True` | Shows the menus behind a ☰ button (`False` always shows their names). | | `start` | `()` | Items after the menus (project, branch…). | | `center` | `None` | Your own widget in the middle instead of the title (a search field, Run and Stop…); the bar still drags on both sides of it. | | `end` | `()` | Items before the window buttons. | | `style` | `None` | `"macos"`, `"windows"`, `"gnome"`, `"ubuntu"` or `"kde"`. By default the window's `frame`, or this system's. | | `window` | `None` | The window the buttons act on. By default the one whose `view()` is running. | | `height` | `None` | Height of the bar. By default the platform's. | | `resize_border` | `6.0` | Width in pixels of the borders that resize the window. | | `resize_edges` | `True` | `False` leaves the resize borders to you (`pz.window_edges`), to put them over menus and dialogs. | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#window_frame) ##### `ui.Menu` ```python @dataclass class Menu(label, items=[]) ``` A menu of a window frame's menu bar: a name and its items (`ui.MenuItem`, `ui.SEPARATOR` or a header string). | Property | Default | Description | | --- | --- | --- | | `label` | *required* | The menu's name. | | `items` | `[]` | Its entries: `ui.MenuItem`, `ui.SEPARATOR` or a header string. | [Full reference →](https://albakore.github.io/pyzed/reference/ui/#menu-1) ##### `ui.window_title_bar` ```python window_title_bar( title=None, *, style=None, start=(), center=None, end=(), on_drag=None, on_minimize=None, on_maximize=None, on_close=None, on_menu=None, maximized=False, focused=True, width='fill', height=None, bg=None, border=True, theme=None, ) ``` A window's title bar alone: window buttons in the style of `style` (on the left for macOS), `start` items, the title and `end` items. Without callbacks it only shows, which is how Pyzed Design previews a form in the frame of each platform. | Property | Default | Description | | --- | --- | --- | | `title` | `None` | Title (centered, or on the left on Windows). | | `style` | `None` | `"macos"`, `"windows"`, `"gnome"`, `"ubuntu"` or `"kde"` (`None`: this system's). | | `start` | `()` | Items at the start. | | `center` | `None` | Widget in the middle instead of the title; the bar still drags on both sides of it. | | `end` | `()` | Items at the end. | | `maximized` | `False` | Shows the restore symbol. | | `focused` | `True` | `False` dims it like a window in the background. | | `width` | `"fill"` | Width: pixels, `"fill"`, `"shrink"` or `"fill:N"` (proportion). | | `height` | `None` | Height. By default the platform's. | | `bg` | `None` | Background color (`"#rrggbb[aa]"`, `(r, g, b[, a])` or `"transparent"`). | | `border` | `True` | Line under the bar. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_drag`, `on_minimize`, `on_maximize`, `on_close`, `on_menu` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#window_title_bar) ##### `ui.window_controls` ```python window_controls( style=None, *, on_minimize=None, on_maximize=None, on_close=None, maximized=False, focused=True, height=None, theme=None, ) ``` The minimize, maximize and close buttons in the style of a platform. A button without a callback is drawn but does nothing. | Property | Default | Description | | --- | --- | --- | | `style` | `None` | `"macos"`, `"windows"`, `"gnome"`, `"ubuntu"` or `"kde"` (`None`: this system's). | | `maximized` | `False` | Shows the restore symbol. | | `focused` | `True` | `False` dims them. | | `height` | `None` | Height. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_minimize`, `on_maximize`, `on_close` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#window_controls) ##### `ui.system_platform` ```python system_platform() ``` The style of this system's window buttons: `"macos"`, `"windows"`, `"kde"`, `"ubuntu"` or `"gnome"` (other Linux desktops). Under WSL it is `"windows"`. [Full reference →](https://albakore.github.io/pyzed/reference/ui/#system_platform) #### Related - [Title bar](https://albakore.github.io/pyzed/library/title-bar/): The top bar with project and branch pickers. - [Workspace](https://albakore.github.io/pyzed/library/workspace/): The layout of an editor-style window: title bar, docks, center, status bar. - [Menu](https://albakore.github.io/pyzed/library/menu/): A context menu with icons, shortcuts and checks. ### Workspace > The layout of an editor-style window: title bar, docks, center, status bar. A Pyzed component for Python desktop GUIs, with examples and its API. Source: https://albakore.github.io/pyzed/library/workspace/ :::tip[In plain words] The whole layout of an editor-like window: bar on top, side panels, the main area and a bar at the bottom. ::: Builds the frame of an editor-style window: the title bar on top, docks on the left, right and bottom, the center and the status bar. Pass `None` to hide a dock (that is how Ctrl+B works); `left_width`, `right_width` and `bottom_height` set their size and `on_resize` reports drags. `ui.workspace` · Category: [Workspace](https://albakore.github.io/pyzed/library/#workspace) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#workspace-1) **Code:** ```python files = ui.TreeNode.from_paths(["src/main.py", "src/ui.py", "README.md"], status={"src/ui.py": "modified"}) ui.workspace( pz.column([ ui.tab_bar([ui.Tab.for_file("src/main.py")], "src/main.py", on_close=on_close), ui.editor("ws-main", "import pyzed as pz\n\n\ndef main():\n pz.run(App)\n", path="main.py"), ]), title_bar=ui.title_bar([ui.title_button("pyzed", chevron=True), ui.title_button("main", icon="git-branch", muted=True)], [ui.icon_button("bell", on_bell, size="sm"), ui.avatar("KV")]), left=pz.column([ui.panel_header("Project", [ui.icon_button("plus", on_new, size="xs")]), ui.tree(files, expanded={"src"}, selected="src/main.py")]), bottom=pz.column([ui.panel_header("Terminal", icon="terminal"), ui.terminal("$ python main.py\n\x1b[32m✓\x1b[0m done")]), status_bar=ui.status_bar([ui.status_item("0", icon="circle-x"), ui.status_item("1", icon="triangle-alert")], [ui.status_item("Ln 4, Col 8"), ui.status_item("Python")]), left_width=200, bottom_height=110, ) ``` #### When to use - As the root of editor-like apps: IDEs, note apps, database clients, file managers. #### Usage ```python import pyzed as pz from pyzed import ui class Ide(pz.App): def __init__(self): self.show_left = True def on_key(self, combo): if combo == "ctrl-b": self.show_left = not self.show_left def view(self): return ui.workspace( self.editor_area(), title_bar=ui.title_bar([ui.title_button("my-project", chevron=True)]), left=self.project_panel() if self.show_left else None, status_bar=ui.status_bar([], [ui.status_item("Python")]), ) ``` #### Variants :::note[About these captures] Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks. ::: ##### Docks ```python ui.workspace(main_view(), status_bar=ui.status_bar([], [ui.status_item("Python")])) ``` ```python ui.workspace(main_view(), left=pz.column([ui.panel_header("Project"), ui.list_item("main.py", icon="file-code", selected=True, inset=True)]), left_width=150) ``` ```python ui.workspace(main_view(), bottom=pz.column([ui.panel_header("Terminal", icon="terminal"), ui.terminal("$ python main.py")]), bottom_height=90) ``` ```python ui.workspace(main_view(), right=pz.column([ui.panel_header("Outline"), ui.list_item("class Notes", icon="box")]), right_width=150) ``` ```python ui.workspace(main_view(), title_bar=ui.title_bar([ui.title_button("pyzed", chevron=True)], [ui.avatar("KV")])) ``` #### Events Workspace has **1 event of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/). | Event | Handler gets | When | | --- | --- | --- | | `on_resize` | `(side, size)` | Called with `(side, size)` when the user finishes resizing a dock by dragging its inner border. | **Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`. ##### Handling the events The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/). **Imperative:** ```python class Ide(pz.App): def __init__(self): self.left_width, self.bottom_height = 220, 160 def resized(self, side, size): # on_resize: which dock and its new size if side == "left": self.left_width = size elif side == "bottom": self.bottom_height = size def view(self): return ui.workspace(main_view(), left=ui.panel_header("Project"), bottom=ui.panel_header("Terminal"), left_width=self.left_width, bottom_height=self.bottom_height, on_resize=self.resized) ``` **Declarative:** ```python from dataclasses import dataclass @dataclass class Resized: side: str size: float class Ide(pz.App): sizes = {"left": 220, "bottom": 160} def update(self, message): match message: case Resized(side, size): self.sizes = {**self.sizes, side: size} def view(self): return ui.workspace(main_view(), left=ui.panel_header("Project"), bottom=ui.panel_header("Terminal"), left_width=self.sizes["left"], bottom_height=self.sizes["bottom"], on_resize=Resized) ``` **Functional:** ```python from dataclasses import dataclass @dataclass(frozen=True) class State: left: float = 220 bottom: float = 160 def view(state, set_state): return ui.workspace(main_view(), left=ui.panel_header("Project"), bottom=ui.panel_header("Terminal"), left_width=state.left, bottom_height=state.bottom, on_resize=lambda side, size: set_state(**{side: size})) ``` #### Properties and API ##### `ui.workspace` ```python workspace( center, *, title_bar=None, left=None, right=None, bottom=None, status_bar=None, left_width=240, right_width=320, bottom_height=220, on_resize=None, theme=None, ) ``` The layout of an editor-style window: title bar, left, right and bottom docks, center and status bar. Pass `None` to hide a dock. | Property | Default | Description | | --- | --- | --- | | `center` | *required* | Central content (usually tabs + editor). | | `title_bar` | `None` | Title bar (`ui.title_bar`). | | `left` | `None` | Left dock. | | `right` | `None` | Right dock. | | `bottom` | `None` | Bottom dock. | | `status_bar` | `None` | Status bar (`ui.status_bar`). | | `left_width` | `240` | Width of the left dock. | | `right_width` | `320` | Width of the right dock. | | `bottom_height` | `220` | Height of the bottom dock. | | `theme` | `None` | Theme to use instead of the current one (`pyzed.theme.current()`). | Events: `on_resize` ([events](#events)). [Full reference →](https://albakore.github.io/pyzed/reference/ui/#workspace-1) #### Related - [Title bar](https://albakore.github.io/pyzed/library/title-bar/): The top bar with project and branch pickers. - [Status bar](https://albakore.github.io/pyzed/library/status-bar/): The bottom bar: diagnostics, cursor position, language. - [Panel](https://albakore.github.io/pyzed/library/panel/): A dockable, resizable side panel. - [Split](https://albakore.github.io/pyzed/library/split/): Two panes with a draggable divider.