UI

ui-elements

Declarative, flexbox-based UI library for building overlays and notifications in the Talon Python runtime.

Install

mkdir -p .claude/skills/ui-elements && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/19438" && unzip -o skill.zip -d .claude/skills/ui-elements && rm skill.zip

Installs to .claude/skills/ui-elements

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Trigger when building or modifying Talon UI, HUD, overlay, notification, cheatsheet, or using ui_elements.
106 chars✓ has a “when” trigger
Intermediate

Key capabilities

  • Construct custom user interfaces using a declarative React-inspired API
  • Implement layout structures using flexbox properties
  • Manage global application state across multiple UI components
  • Render visual elements on a Skia canvas
  • Handle user interactions like clicks and state changes

How it works

The library provides a declarative API that maps to a Skia canvas, allowing developers to define UI components and layouts using flexbox within Talon's Python runtime.

Inputs & outputs

You give it
Python code defining UI elements and state
You get back
Rendered visual interface on a Skia canvas

When to use ui-elements

  • Create a custom voice control HUD
  • Build a persistent UI overlay for Talon
  • Design interactive notifications
  • Develop a cheatsheet UI component

About this skill

talon-ui-elements

Python canvas UI library for Talon voice control runtime.

  • NOT web/browser - renders on a Skia canvas. No HTML, CSS, DOM, or browser APIs.
  • Everything is flexbox. No display: block/inline/grid. Every container is a flex container.
  • flex_direction defaults to "column" - children stack vertically. Use flex_direction="row" for horizontal.
  • align_items defaults to "stretch" on containers (divs), "flex_start" on screen.
  • Runs inside Talon's Python runtime (no pip, no virtualenv, no build step). Talon hot-reloads .py files on save.
  • React-inspired declarative API with CSS-like properties (flexbox layout, styling kwargs).
  • Import: from talon import actions → call actions.user.ui_elements(["div", "text", "screen", ...]) to get element constructors.
  • All UI code lives in plain .py files inside the Talon user directory.

Minimal Example

from talon import actions

def hello_world_ui():
    div, text, screen = actions.user.ui_elements(["div", "text", "screen"])

    return screen(justify_content="center", align_items="center")[
        div(background_color="#333333", padding=16, border_radius=8, border_width=1)[
            text("Hello world", color="#FFFFFF", font_size=24)
        ]
    ]

def show_hello_world():
    actions.user.ui_elements_show(hello_world_ui)

def hide_hello_world():
    actions.user.ui_elements_hide(hello_world_ui)

def toggle_hello_world():
    actions.user.ui_elements_toggle(hello_world_ui)

Getting Elements

Destructure element constructors from actions.user.ui_elements(...):

div, text, screen = actions.user.ui_elements(["div", "text", "screen"])
button, input_text, state = actions.user.ui_elements(["button", "input_text", "state"])
ref, effect, icon = actions.user.ui_elements(["ref", "effect", "icon"])
style, component = actions.user.ui_elements(["style", "component"])
window = actions.user.ui_elements("window")  # single element returns directly

All elements: div, text, code, screen, button, input_text, textarea, select, data_table, form, state, ref, effect, icon, style, component, link, checkbox, switch, table, tr, td, th, window, active_window

SVG elements (must be used inside svg()): svg, path, rect, circle, line, polyline, polygon


Element Hierarchy

  • Root must be screen() or active_window()
  • Children via bracket syntax: parent()[child1, child2]
  • Containers (can have children): div, form, window, table, tr, td, th, screen, active_window, svg
  • Leaves (no children): text, code, icon, checkbox, switch, input_text, textarea, select, data_table, link
  • button: leaf with label button("Click"), container without: button(on_click=fn)[icon("check")]
  • Dynamic lists: div()[*[text(item) for item in items]]

See patterns.md for common layout patterns, tab navigation, and complete examples.


Properties Quick Reference

All properties are kwargs: div(background_color="333333", padding=16).

  • Layout: flex_direction ("column"/"row"), justify_content, align_items, align_self, flex, gap, flex_wrap
  • Sizing: width, height, min_width, max_width, min_height, max_height - pixels or "100%"
  • Spacing: padding, margin - plus _top, _right, _bottom, _left variants
  • Position: position ("static"/"relative"/"absolute"/"fixed"), top, left, right, bottom
  • Colors: background_color, color, border_color - hex strings ("FF0000", "#FF0000", "FF000080") or named colors
  • Gradients: background="linear_gradient(to_right, FF0000, 0000FF)" - directions: to_right, to_left, to_bottom, to_top, or angle like 45deg
  • Font: font_size (default 16), font_weight ("normal"/"bold"), font_family, text_align ("left"/"center"/"right"), white_space ("normal"/"nowrap")
  • Border: border_width, border_radius, border_color - plus individual sides (border_top, etc.)
  • Interactivity: on_click, on_change, highlight_style, disabled, draggable, drag_handle, autofocus
  • Animation: transition, mount_style, unmount_style
  • Identity: id, key, class_name, z_index
  • Scrolling: overflow / overflow_y / overflow_x = "scroll" | "hidden"
  • Other: opacity (0.0-1.0, cascades), drop_shadow

See properties.md for full tables with types and defaults.


State Management

All state is global - any UI or voice command can read/write any key. State is shared across UIs, so one UI can react to state set by another UI or by a voice command.

state = actions.user.ui_elements("state")

value = state.get("key", default)                    # Read-only snapshot
value, set_value = state.use("key", default)         # Reactive (triggers re-render)
state.set("key", new_value)                          # Set directly

set_value(lambda prev: prev + 1)                     # Lambda setter
set_items(lambda prev: prev + [new_item])            # Append to list

External access (from voice commands / outside UI):

actions.user.ui_elements_set_state("key", value)
actions.user.ui_elements_set_state("count", lambda prev: prev + 1)
actions.user.ui_elements_set_state({"key1": "val1", "key2": "val2"})  # batch
actions.user.ui_elements_get_state("key")
actions.user.ui_elements_get_state("key", "default_value")

Initial state (pre-set before first render):

actions.user.ui_elements_show(my_ui, initial_state={"tab": "home", "items": []})

See: docs/concepts/state.md


Refs

Direct element access for input fields. Requires matching id prop. Only use in callbacks or effects, not during initial render.

ref = actions.user.ui_elements("ref")
input_ref = ref("my_input")

input_ref.value       # Read current value
input_ref.clear()     # Clear the input
input_ref.focus()     # Focus the input

See: docs/concepts/ref.md


Effects (Lifecycle)

effect = actions.user.ui_elements("effect")

# Mount only:
effect(on_mount, [])

# Mount + unmount:
effect(on_mount, on_unmount, [])

# State change:
effect(on_tab_change, ["active_tab"])  # deps are string state key names

# Mount with cleanup:
def on_mount():
    return lambda: print("Cleanup!")
effect(on_mount, [])

See: docs/concepts/effect.md


Style Blocks

CSS-like selectors for shared styles:

style = actions.user.ui_elements("style")

style({
    "*": {"color": "CCCCCC"},                        # Universal
    "text": {"font_size": 14},                       # Tag selector
    "#my_id": {"background_color": "333333"},        # ID selector
    ".my_class": {"padding": 12, "border_radius": 6},  # Class selector
})

button("Click", class_name="my_class")

See: docs/concepts/style.md


Elements Quick Reference

  • screen() / active_window() - Root containers. screen(1) for second monitor. active_window() follows focused OS window.
  • div() - Generic container.
  • text("content") - Display text.
  • code("def hello():") - Syntax-highlighted code. Props: language ("python"/"talon"), theme, diff=True, copyable=True. Monospace font by default.
  • form(on_submit=fn) - Form container. Enter in child input_text or clicking a child button(type="submit") triggers on_submit. Callback receives SubmitEvent(data={"input_id": "value", ...}) with all child input values. Ctrl+Enter submits from textarea.
  • button("label", on_click=fn) - Interactive button. Container when no label: button(on_click=fn)[icon("check")]. Use type="submit" inside a form to trigger the form's on_submit.
  • input_text(id="x") - Text input. Requires id. Supports placeholder, autofocus, on_change.
  • textarea(id="x", rows=5) - Multi-line input. Requires id.
  • select(id="x", options=[...]) - Dropdown. Requires id. Options: strings or {"label": "...", "value": "..."} dicts.
  • checkbox(checked=True, on_change=fn) - Toggle. Uses on_change not on_click.
  • switch(checked=True, on_change=fn, animated=True) - Toggle switch. Uses on_change not on_click. animated enables smooth transitions. size scales dimensions (default 14).
  • link("text", url="...") - Clickable URL. close_on_click=True to hide UI after click.
  • icon("name", size=24) - Built-in SVG icon (Lucide-style, 24x24 viewbox). ~48 available names: arrow_down, arrow_left, arrow_right, arrow_up, check, chevron_down, chevron_left, chevron_right, chevron_up, close, clock, copy, delta, diamond, download, edit, external_link, file, file_text, folder, home, maximize, menu, mic, minimize, minus, more_horizontal, more_vertical, multiply, pause, play, plus, rotate_left, settings, shrink, star, stop, trash, upload.
  • window(title="...") - Draggable panel with title bar, minimize, close buttons.
  • table() / tr() / th() / td() - Table structure.
  • component(fn, props) - Reusable UI with local state (state.use_local). Only needed for local state or scoped styles.
  • svg() / path() / rect() / circle() / line() - Custom SVG. Use size and view_box, not width/height/viewBox. Icons use a 24x24 viewbox. To create a custom icon:
svg, path, circle = actions.user.ui_elements(["svg", "path", "circle"])
# defaults: size=24, view_box="0 0 24 24", stroke_width=2, stroke_linecap/linejoin="round"
svg()[
    circle(cx=12, cy=12, r=10),
    path(d="M12 6v6l4 2"),
]

See: docs/elements.md


Show / Hide API

actions.user.ui_elements_show(my_ui)                                    # Show
actions.user.ui_elements_show(my_ui, initial_state={...})               # With initial state
actions.user.ui_elements_show(my_ui, duration="2s")                     # Auto-hide
actions.user.ui_elements_show(my_ui, on_mount=fn, on_unmount=fn) 

---

*Content truncated.*

When not to use it

  • Building web or browser-based interfaces
  • Using HTML, CSS, or DOM APIs
  • Projects requiring non-Talon runtime environments

Prerequisites

Talon voice control runtime

Limitations

  • No support for standard web technologies like HTML or CSS
  • Ref values are unavailable during initial render
  • Checkbox and switch elements require on_change instead of on_click

How it compares

Unlike standard web development, this library renders directly to a Skia canvas within the Talon environment without using HTML, CSS, or browser APIs.

Compared to similar skills

ui-elements side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
ui-elements (this skill)03moNo flagsIntermediate
gemini-logo-remover97moReviewBeginner
slack-gif-creator63moReviewIntermediate
nano-image-generator15moReviewBeginner

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

gemini-logo-remover

bear2u

Remove Gemini logos, watermarks, or AI-generated image markers using OpenCV inpainting. Use this skill when the user asks to remove Gemini logo, AI watermark, or any logo/watermark from images.

9115

slack-gif-creator

anthropics

Knowledge and utilities for creating animated GIFs optimized for Slack. Provides constraints, validation tools, and animation concepts. Use when users request animated GIFs for Slack like "make me a GIF of X doing Y for Slack."

698

nano-image-generator

solidSpoon

Generate images using Nano Banana Pro (Gemini 3 Pro Preview). Use when creating app icons, logos, UI graphics, marketing banners, social media images, illustrations, diagrams, or any visual assets. Triggers include phrases like 'generate an image', 'create a graphic', 'make an icon', 'design a logo', 'create a banner', or any request needing visual content.

110

image-crop-rotate

instavm

Image processing skill for cropping images to 50% from center and rotating them 90 degrees clockwise. This skill should be used when users request image cropping to center, image rotation, or both operations combined on image files.

05

sora

davila7

Use when the user asks to generate, remix, poll, list, download, or delete Sora videos via OpenAI’s video API using the bundled CLI (`scripts/sora.py`), including requests like “generate AI video,” “Sora,” “video remix,” “download video/thumbnail/spritesheet,” and batch video generation; requires `OPENAI_API_KEY` and Sora API access.

23

post-process-logo

tradingstrategy-ai

Post-process original logos into standardised 256x256 PNG format

12

Search skills

Search the agent skills registry