API Reference

February 18, 2026 · View on GitHub

Complete reference for all public cute.* functions.

Application

cute.app(title, width, height, block)

Creates a window and runs the Qt event loop. The block builds the UI tree.

cute.app("My App", 800, 600) do
  # build UI here
end

cute.quit()

Exits the application.

cute.window()

Returns the raw QWidget handle for the main window.

cute.stylesheet(css_or_state)

Applies a Qt stylesheet (CSS string) to the entire window. Also accepts a state or computed state — the stylesheet re-applies automatically when it changes.

cute.stylesheet("QLabel { color: red; }")

# Reactive — auto-updates when font_size changes
css = cute.computed(font_size, fn(size)
  result = "QWidget { font-size: #{size}px; }"
  result
end)
cute.stylesheet(css)

Layouts

cute.vbox(props = nil, block)

Vertical box layout. Widgets stack top-to-bottom. Returns the QVBoxLayout handle.

cute.vbox do
  cute.label("Top")
  cute.label("Bottom")
end

cute.vbox({spacing: 8, margins: [12, 8, 12, 8]}) do
  cute.label("Spaced")
end

cute.hbox(props = nil, block)

Horizontal box layout. Widgets stack left-to-right. Returns the QHBoxLayout handle.

cute.hbox({spacing: 4}) do
  cute.button("Left")
  cute.spacer()
  cute.button("Right")
end

cute.scroll(props = nil, block)

Scrollable area. Content inside the block is placed in a scrollable viewport. Returns QScrollArea handle.

cute.scroll({css: "background: #fff;"}) do
  # scrollable content
end

cute.spacer()

Inserts a stretch spacer that pushes subsequent widgets to the end of the layout.

cute.separator()

Inserts a horizontal separator line. Returns QFrame handle.

cute.container(props = nil, block)

A QWidget wrapper that holds an inner vertical layout. Props are split: spacing and margins go to the inner layout, everything else (css, width, height, etc.) goes to the widget. Returns the QWidget handle.

cute.container({css: "background: #1e1e2e;", spacing: 8}) do
  cute.label("Inside a container")
  cute.button("Click me")
end

cute.new_hbox(props = nil)

Creates a free-standing QHBoxLayout that is not added to the current layout context. Use with layout.add_layout() or as a row in cute.flow.

row = cute.new_hbox({spacing: 12})
cute.add_widget(row, card1)
cute.add_widget(row, card2)

Widgets

All widget functions automatically add to the current layout and return the raw Qt handle.

cute.label(text_or_state, arg2 = nil, arg3 = nil)

Text label. Returns QLabel.

Static text:

cute.label("Hello")
cute.label("Title", {css: "font-weight: bold;"})

State-aware — auto-updates when the state changes:

cute.label(count)                                   # displays value as string
cute.label(count, fn(v) "Count: #{v}" end)          # with transform
cute.label(count, fn(v) "#{v}" end, {width: 200})   # with transform and props

cute.button(text, arg1 = nil, arg2 = nil)

Push button. Use do...end for the click handler. Optional props hash for inline styling. Returns QPushButton.

cute.button("Click") do
  puts "clicked"
end

cute.button("Submit", {css: "color: green;"}) do
  save_data()
end

cute.input(placeholder = "", props = nil)

Text input field. placeholder is a hint string. Returns QLineEdit.

Two-way state binding via the state: prop key:

name = cute.state("")
cute.input("Enter name", {state: name})
# name.get() reflects input text; name.set() updates it

cute.checkbox(text, arg1 = nil, arg2 = nil)

Checkbox. on_change receives the check state (0 = off, 2 = on). Returns QCheckBox.

cute.checkbox("Dark mode") do |state|
  toggle_theme(state)
end

cute.checkbox("Dark mode", {css: "color: #ccc;"}) do |state|
  toggle_theme(state)
end

cute.combo(items, arg1 = nil, arg2 = nil)

Dropdown. items is a string array. on_change receives the selected text. Returns QComboBox.

cute.combo(["Red", "Green", "Blue"], fn(text)
  puts "Selected: #{text}"
end)

cute.combo(["A", "B", "C"], {width: 120}, fn(text)
  puts text
end)

cute.list_widget(props = nil)

Scrollable list for manual item management. Use .add_item(text) to add items and .clear() to remove all. Returns QListWidget.

cute.list(items_state, render_fn, on_select = nil)

Reactive list bound to a state. Re-renders automatically when the state changes. Returns QListWidget.

render_fn receives (item, index) and returns display text. on_select receives the selected row index.

items = cute.state(["Apple", "Banana", "Cherry"])
cute.list(items, fn(item, i) "#{i + 1}. #{item}" end, fn(row)
  puts "Selected row #{row}"
end)

# Re-renders automatically:
items.set(["X", "Y", "Z"])

More Widgets

cute.image(props = nil)

Displays a QLabel configured as an image placeholder. Set the pixmap later via label.set_pixmap(pixmap). Returns the QLabel handle.

img = cute.image({width: 200, height: 200})
# Later, after loading:
img.set_pixmap(pixmap)

cute.canvas(props = nil, draw_fn = nil)

Composition-based drawing widget backed by a QLabel.

draw_fn(ctx, size, state_value) is called on creation and resize. If props["state"] is provided, it is also called whenever that state changes, and state_value receives the current state value.

ctx exposes drawing methods:

  • ctx.fill(color)
  • ctx.line(x1, y1, x2, y2, color = nil)
  • ctx.text(x, y, text, color = nil)

size is a hash with width and height.

phase = cute.state(0)
canvas = cute.canvas({min_height: 180, state: phase}, fn(ctx, size, v)
  w = size["width"]
  ctx.fill("#11111b")
  ctx.line(10, 20, w - 10, 20, "#89b4fa")
  ctx.text(12, 40, "phase: #{v}", "#cdd6f4")
end)

cute.canvas_frame(width, height, bg = nil)

Creates an internal frame object for canvas drawing.

cute.canvas_fill(frame, color)

Fills an existing frame (advanced usage).

cute.canvas_line(frame, x1, y1, x2, y2, color = nil)

Draws a line on an existing frame (advanced usage).

cute.canvas_text(frame, x, y, text, color = nil)

Draws text on an existing frame (advanced usage).

cute.canvas_commit(canvas, frame)

Assigns the frame result to the canvas widget.

cute.load_pixmap(data)

Converts raw image bytes (e.g., from http.get().body_bytes) into a QPixmap. Returns nil if the data cannot be decoded.

resp = http.get("https://picsum.photos/200/200")
pix = cute.load_pixmap(resp.body_bytes)
if pix != nil
  img.set_pixmap(pix)
end

cute.text_area(text = "", props = nil)

Multi-line read-only text area. Returns QPlainTextEdit with editing disabled.

cute.text_area("Long text here...", {min_height: 200})

cute.progress(props = nil)

Indeterminate progress bar (range 0..0). Apply props like min_width or css. Returns QProgressBar.

bar = cute.progress({min_width: 200})
# To show determinate progress, set range and value on the handle:
# bar.set_range(0, 100); bar.set_value(50)

cute.slider(min, max, arg1 = nil, arg2 = nil)

Horizontal slider. arg1 can be a props hash or a change callback; arg2 is the callback if arg1 is props. Returns QSlider.

cute.slider(0, 100, fn(val)
  puts "Value: #{val}"
end)

cute.slider(10, 50, {width: 200}, fn(val)
  volume.set(val)
end)

cute.group(title, props = nil, block)

Group box with a title and inner vertical layout. Returns the QGroupBox handle.

cute.group("Settings") do
  cute.checkbox("Enable notifications")
  cute.checkbox("Dark mode")
end

cute.tabs(props = nil, block)

Tabbed widget container. Use cute.tab inside the block to add pages. Returns QTabWidget.

cute.tabs do
  cute.tab("General") do
    cute.label("General settings")
  end
  cute.tab("Advanced") do
    cute.label("Advanced settings")
  end
end

cute.tab(title, props = nil, block)

A single tab page inside cute.tabs. Creates a QWidget with a vertical layout and adds it as a tab. Returns the page QWidget.


Properties

cute.props(widget, hash)

Applies a property hash to any widget or layout. Returns the widget.

KeyTypeEffect
idstringset_object_name (for CSS #id targeting)
widthintset_fixed_width
heightintset_fixed_height
min_widthintset_minimum_width
min_heightintset_minimum_height
max_widthintset_maximum_width
max_heightintset_maximum_height
visibleboolset_visible
enabledboolset_enabled
tooltipstringset_tool_tip
cssstringset_style_sheet (per-widget CSS)
wrapboolset_word_wrap
alignstringset_alignment"left", "center", "right"
marginsarrayset_contents_margins[l, t, r, b] or [h, v]
spacingintset_spacing (layouts only)

cute.style(hash)

Builds a CSS property string from a hash. Returns a string.

KeyTypeCSS
bgstringbackground: <value>
colorstringcolor: <value>
sizeintfont-size: <value>px
boldboolfont-weight: bold
italicboolfont-style: italic
familystringfont-family: <value>
paddingint/arraypadding: <value>
marginint/arraymargin: <value>
borderstringborder: <value>
radiusintborder-radius: <value>px

State

cute.state(initial)

Creates a reactive state container. Returns a hash with:

  • .get() — returns the current value
  • .set(value) — updates and notifies observers
  • .update(fn) — transform in place: count.update(fn(v) v + 1 end)
  • .on(fn(value)) — registers a change callback
count = cute.state(0)
count.update(fn(v) v + 1 end)   # 1
count.on(fn(v) puts "now #{v}" end)
count.set(10)                    # prints: now 10

cute.computed(source, transform)

Creates a derived state that auto-updates when the source changes. Returns a read-only state (has .get() and .on()).

count = cute.state(0)
display = cute.computed(count, fn(v) "Count: #{v}" end)
cute.label(display)   # auto-updates when count changes

Works anywhere state is accepted: labels, stylesheets, bind, etc.

cute.bind(state, widget, prop, transform = nil)

Binds a state to a widget property. Sets the initial value and auto-updates on changes.

Supported property names: "text", "visible", "enabled", "css", "tooltip".

status = cute.state("Ready")
lbl = cute.label("Ready")
cute.bind(status, lbl, "text")

# With transform:
cute.bind(count, lbl, "text", fn(v) "Count: #{v}" end)

Events

cute.shortcut(key, callback)

Binds a keyboard shortcut. key uses Qt's key sequence format (e.g., "Ctrl+Q", "F5"). Returns QShortcut handle.

cute.after(ms, callback)

Single-shot timer. Fires callback once after ms milliseconds. Returns QTimer handle.

cute.timer(ms, callback)

Repeating timer. Fires callback every ms milliseconds. Call .stop() on the returned handle to cancel.

cute.on_resize(widget, callback, interval_ms = 200)

Polls widget for size changes every interval_ms milliseconds. Calls callback(width, height) when the size differs from the previous check. Returns the QTimer handle (.stop() to cancel).

cute.on_resize(cute.window(), fn(w, h)
  cols = w / 280
  reflow(cols)
end)

cute.on_double_click(widget, callback)

Detects double-click on any widget. Creates a transparent overlay button that fires callback when two clicks occur within 400ms. Shows a pointing-hand cursor and subtle hover highlight. The overlay auto-resizes with the widget. Returns the overlay button handle.

cute.on_double_click(card, fn()
  show_detail(card)
end)

Dynamic Layout

cute.add_to(layout, block)

Pushes layout onto the context stack and runs block. Any cute.* widget calls inside the block are auto-parented to this layout. Use this to add widgets to a layout after initial construction.

cute.add_to(card_layout) do
  cute.label("Added later")
end

cute.detached(layout, block)

Builds a widget tree via the Cute DSL, then detaches the result from the layout and returns it as a hidden QWidget. The widget can later be placed with cute.add_widget or cute.flow.

card = cute.detached(grid) do
  cute.container({css: "background: #333;"}) do
    cute.label("Hello")
  end
end

cute.clear_layout(layout)

Removes all items from a layout back-to-front. Child widgets are not destroyed -- they can be re-added. Spacer and stretch items are discarded.

cute.clear_layout(grid)

cute.add_widget(layout, widget)

Appends an existing widget to a layout and calls .show() on it.

cute.add_widget(row, card)

cute.add_stretch(layout)

Appends an expanding spacer to a layout.

cute.flow(layout, items, cols, props = nil)

Arranges an array of widgets into a grid inside a vertical layout. Clears the layout first, then creates hbox rows of cols columns. Each row gets a trailing stretch for left-alignment.

ParamTypeDescription
layoutQVBoxLayoutThe container layout to fill
itemsarrayWidgets to arrange
colsintNumber of columns per row
propshashOptional -- passed to each row's hbox (e.g., {spacing: 12})
cute.flow(grid, cards, 3, {spacing: 12})

Dialogs

cute.alert(title, message)

Shows an information dialog.

cute.confirm(title, message)

Shows a Yes/No dialog. Returns true if Yes is clicked.


Threading

cute.ui(callback)

Runs callback on the Qt main thread and blocks until it completes. Use this from inside spawn blocks to safely update widgets.

spawn
  data = fetch_data()
  cute.ui do
    lbl.set_text(data)
  end
end

cute.fetch(work, on_done)

Runs work in a background thread and dispatches the result to the UI thread. Combines spawn + cute.ui() into one call.

cute.fetch(fn() http.get(url) end, fn(resp)
  lbl.set_text(resp.body)
end)